FATALERROR

介绍

我们在调试一些纯 swift 类型出现类似数组越界等情况时,控制台得到的报错信息会和调试 NSObject 子类时不太一样,比如在使用 NSArray 时:

1
2
3
4
5
6
let array : NSArray = [1, 2, 3]
array[100]
// 输出:
// *** Terminating app due to uncaught exception 'NSRangeException',
// reason: '*** -[__NSArrayI objectAtIndex:]:
// index 100 beyond bounds [0 .. 2]'

而如果我们使用 Swift 类型的话:

1
2
3
4
let array = [1,2,3]
array[100]
// 输出:
// fatal error: Array index out of range

调试时,我们可以使用 assert 来排除这样的问题,但是断言值在 Debug 环境中有效,而在 Release 编译中所有的断言都将被禁用。在遇到确实因为输入的错误无法使程序继续运行的时候,我们一般考虑以产生致命错误(fatalError)的方式来终止程序。

fatalError 的使用非常简单,它的 API 和断言比较相似

1
2
3
@noreturn func fatalError(@autoclosure message: () -> String = default,
file: StaticString = default,
line: UInt = default)

@noretrun 表示调用这个方法的话可以不再需要返回,因为整个程序都将终止。

应用

在我们实际自己编码的时候,经常会有不想让别人调用某个方法,但又不得不将其暴露出来的时候。一个最常见并且合理的需求就是“抽象类型或者抽象函数”。在很多语言中都有这样的特性:父类定义了某个方法,但是自己并不给出具体实现,而是要求继承它的子类去实现这个方法,而在 Objective-C 和 Swift 中都没有直接的这样的抽象函数语法支持,虽然在 Cocoa 中对于这类需求我们有时候会转为依赖接口和委托的设计模式来变通地实现,但是其实 Apple 自己在 Cocoa 中也有很多类似抽象函数的设计。比如 UIActivity 的子类必须要实现一大堆指定的方法,而正因为缺少抽象函数机制,这些方法都必须在文档中写明。

在面对这种情况时,为了确保子类实现这些方法,而父类中的方法不被错误地调用,我们就可以利用fatalError 来在父类中强制抛出错误,以保证使用这些代码的开发者留意到他们必须在自己的子类中实现相关方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class MyClass {
func methodMustBeImplementedInSubclass() {
fatalError("这个方法必须在子类中被重写")
}
}

class YourClass: MyClass {
override func methodMustBeImplementedInSubclass() {
print("YourClass 实现了该方法")
}
}

class TheirClass: MyClass {
func someOtherMethod() {

}
}

YourClass().methodMustBeImplementedInSubclass()
// YourClass 实现了该方法

TheirClass().methodMustBeImplementedInSubclass()
// 这个方法必须在子类中被重写
文章作者: Ammar
文章链接: http://lizhaoloveit.cn/2016/04/22/FATALERROR/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Ammar's Blog
打赏
  • 微信
  • 支付宝

评论