美文网首页面试题目iOS理论基础Interview
Objc中向一个nil对象发送消息会怎样

Objc中向一个nil对象发送消息会怎样

作者: 高浩浩浩浩浩浩 | 来源:发表于2017-12-25 16:52 被阅读162次
    先说结论:OC中向nil发消息,程序是不会崩溃的。

    因为OC的函数都是通过objc_msgSend进行消息发送来实现的,相对于C和C++来说,对于空指针的操作会引起crash问题,而objc_msgSend会通过判断self来决定是否发送消息,如果self为nil,那么selector也会为空,直接返回,不会出现问题。视方法返回值,向nil发消息可能会返回nil(返回值为对象),0(返回值为一些基础数据)或0X0(返回值为id)等。但对于[NSNull null]对象发送消息时,是会crash的,因为NSNull类只有一个null方法。

    但是有人会说,如果向一个nil对象发消息不会crash的话,那么unrecognized selector sent to instance的错误是怎么回事?

    这是因为这个对象已经被释放了(引用计数为0了),那么这个时候再去调用方法肯定是会Crash的,因为这个时候这个对象就是一个野指针(指向僵尸对象(对象的引用计数为0,指针指向的内存已经不可用)的指针)了,安全的做法是释放后将对象重新置为nil,使它成为一个空指针,大家可以在关闭ARC后手动release对象验证一下。


    重点:这里要区别的是空指针和野指针的区别!

    空指针:

    1> 没有存储任何内存地址的指针就称为空指针(NULL指针)
    2> 空指针就是被赋值为0的指针,在没有被具体初始化之前,其值为0。

    野指针:

    "野指针"不是NULL指针,是指向"垃圾"内存(不可用内存)的指针。野指针是非常危险的。

    看下面的代码例子:

        Student *stu = [[Student alloc] init];
    
        [stu setAge:10];
    
        [stu release];
    
        [stu setAge:10];
    

    最后一行就出现了野指针错误!

    1. 在执行完第1行代码后,内存中有个指针变量stu,指向了Student对象

      image.png
      假设Student对象的地址为0xff43,指针变量的地址为0xee45,stu中存储的是Student对象的地址0xff43.即指针变量stu指向了这个Student对象。
    2. 在执行完[stu release];给stu指向的Student对象发送了一条release消息。在这里,Student对象接收到release消息后,会马上被销毁,所占用的内存会被回收。

      image.png
      Student对象被销毁了,地址为0xff43的内存地址就变成了“垃圾内存”,然而,指针变量stu仍然指向这一块内存,这时候,stu就称为野指针
    3. 最后一行代码给stu所指向的Student对象发送了一条setAge:消息。但是Student独享已经被销毁了,他所占用的内存已经是垃圾内存,如果你还去访问这一块内存,那么就会报野指针错误。这块内存已经不可用了,也不属于你了,你还去访问他,肯定是不合法的。所以会产生unrecognized selector sent to instancecrash。

    调整代码如下,就可以避免crash

    Student *stu = [[Student alloc] init];
    
     [stu setAge:10];
    
     [stu release];
    
     stu = nil;
    
     [stu setAge:10];
    
    image.png

    这里把stu变成空指针,没有指向任何对象,因此下面的setAge:消息发不出去的,不会造成任何影响。也就不会crash。

    总结

    1> 利用野指针发消息是很危险的,会报错。也就是说,如果一个对象已经被回收了,就不要再去操作它,不要再尝试给它发消息。
    2> 利用空指针发消息是没有任何问题的


    相关连接:

    1. 空指针和野指针
    2. OC中给空对象发送消息程序会Crash吗?

    相关文章

      网友评论

        本文标题:Objc中向一个nil对象发送消息会怎样

        本文链接:https://www.haomeiwen.com/subject/gsvowxtx.html