既然给空指针发送消息不会崩溃,那么我们是否还有必要在发消息前判断一下指针是否为空?

在知乎上有人问到说,斯坦福课程里推荐不用判断 nil。但是有时候不判断 nil 又会导致程序崩溃,例如往 NSArray 里插入一个 nil 的情况。

以下是我的回答:

不管斯坦福怎么说,我的建议是如果这个指针可能为空,那么用之前都做一下判断。

为什么这么建议呢?

首先,最实际的理由是,给空指针发消息是非常慢的,而做一下 if 判断是否为空是非常快的操作。
这个速度上的差别是百倍这个单位的。

为什么呢?因为给 nil 发消息这件事情是在运行时判断的,而系统也并非简单的丢掉这个消息,系统还需要判断这个消息是否需要返回值,如果需要,还要判断返回值的类型:如果返回指针、数字、真伪等,则返回 0,如果返回的是 OS 定义过的数据结构,那么会返回一个被填充上 0 的结构回来,如果返回的是其它类型,则系统会返回一个未定义的类型回来。而一个 if,则能够直接跳过这些运行时的处理。

我做过一个实验:

分别是两个100万次的循环,其中一个给 nil 对象发送了 100万次消息,另外一个循环在发消息前,会判断一下该对象是否为空。

实验的结果是两个循环的执行时间相差了200多倍。这还是消息中没有传任何参数的情况。

这就好像我们不建议用 try cache 来做本可以用 if else 判断掉的错误处理一样,因为开销太大。

另外,“给空指针发消息不会崩溃”是语言特性,是为了防止人为失误导致程序崩溃的“保险”机制。我们写代码时应该尽量避免依赖语言特性的写法,因为这不利于代码(逻辑)移植,语言特性本身也是会变化的(哪怕变化的可能性为零)。

最后,这能养成一个好习惯,培养出一个好的思维方式。上述的这种遇到“错误”也让程序继续跑下去的语言特性本身就是有争议的,虽然给 nil 发消息不会崩溃,但也正是由于程序不会崩溃,当你的代码写错时你也无法察觉到,你的程序有可能会进入一个你完全没有预期到的状态,看似一切正常,但返回的结果却是完全错误的。而写代码时花1秒钟加一个简单的 if 判断,就能够清楚地看出哪个指针是可能为空的,这些信息在分析代码问题的时候是非常宝贵的。