zoukankan      html  css  js  c++  java
  • Object -c基础知识(5)--release 之后 retainCount为何为1

    在XCode中加入如下代码:
     UILabel *label=[UILabel alloc];
    [label setText:@"TestLabel"];
    NSLog(@"%d",[label retainCount]);
    [label release];
    NSLog(@"%d",[label retainCount]);
    理论上说,第一句话alloc了一个label,其保留计数器值为1,第二句话对保留计数器的值不产生影响,第4句话release了label,其保留计数器的值应该变为0,从而调用dealloc方法销毁label,但事实上,NSLog输出的结果为:
     1
     1 
    两个NSLog结果都是1,更为奇怪的是,如果在第二个NSLog之前加上一句NSLog,内容任意,如下:
    UILabel *label=[UILabel alloc];
    [label setText:@"TestLabel"];
    NSLog(@"%d",[label retainCount]);
    [label release];
    NSLog(@"Anything Else");
    NSLog(@"%d",[label retainCount]);
     
    此时,原来的第二个NSLog会出现EXEC_BAD_ACCESS错误,如下:
    self.window.rootViewController * self.viewController;   EXC_BAD_ACCESS 错误
    NSLog输出结果为:
    1
    Anything Else
    ...错误代码.....
     
    这里虽然出现了错误,但这样的结果反而是正确的,因为在NSLog之前,label已经被dealloc,这时发送给label的消息应该都不能被响应,会出现EXEC_BAD_ACCESS错误;但是,为什么之前第一种代码写法不是这样的情况呢?
    根据网上查阅的资料,也许可以得出以下结论,事实上label的确已经被dealloc了,保留计数器的值也已经变成0了,其原来占用的内存也已经不可用 了,但是原来这块内存中的内容还没有变(标记删除),将会在未来某个不确定的时间上被清理 ,这就是为什么NSLog输出的label保留计数器的值仍为1,而如果在此 之前再加上一个NSLog,则改变了原来这块内存的内容,于是发送给label的消息不再会被响应,于是程序crash。
    值得一提的是,并不是加了一句NSLog之后就一定会造成程序crash的,如果那句新加的NSLog没有占用原来label的内存,那下一句NSLog依旧能够响应发送给label的消息,结果会类似第一种代码所产生的结果,具体如下:
    1
    Anything Else
    1
     
    所以说,两种情况都是有可能发生的,至于到底发生哪种情况,完全取决于合适系统清理掉label占用的内存,也可以说取决于“运气”,因为这个时间是不确定的。由于苹果源码非开源,所以究竟是什么样的都知识猜测,以上内容皆网上结果,本人认为retaincount最后为1.永远不可能为0.具体论证如下:
    老师模拟了release内部实现大致算法:
    release()
    {
    if(retainCount>1)
    retainCount--;
    else
    {dealloc();}
    }
     
    于是可以看出retainCount最终为1的时候执行了dealloc();dealloc在类中实现了重写,所以retainCount=1的时候进行了release()会自然的想到retainCount=0,这是多数人的自然思维.其实retainCount=1的时候进行release()就会执行dealloc(),外部实现了重写dealloc()方法,所以这就是为什么程序retainCount=1的时候再次release()就会销毁程序然后系统自然调用dealloc()的原因.
    比如:

    Student *stu=[Studentnew];//retainCount=1

    [stu retain];  //retainCount=2;

    [stu release];//执行如 release(){if(retainCount>1)retainCount--;else{dealloc();}}的操作   retainCount=1

    [stu release];//执行如 release()内部的else中的操作 调用dealloc()方法,外部实现了重写,故:调用dealloc();  此时retainCount=1 .

    如果不加僵尸模式可以测试出来,在dealloc()函数中NSLog();一下,可以输出两次结果.

    为什么可以输出两次结果而不是三次四次?请看如下dealloc实现代码:

    -(void)dealloc

    {    NSLog(@"------->AA");

        [super dealloc];//调用了父类的dealloc();

    }

    以上重写的dealloc()函数内部进行了父类的dealloc()方法调用,第一次retainCount=1的时候进行release(),会正常执行dealloc()并打印结果,此时进行了 [super dealloc];父类被销毁,清空内存中内容,标记删除.当再次执行release()的时候,retainCount=1不变,进行else中内容的操作,执行dealloc(),dealloc()函数内容还是先NSLog();输出的时候没有问题,当执行到 [super dealloc];的时候才出问题,说明程序crash掉是因为父类被dealloc()的缘故,但是retainCount的值仍然是1.根据super()的dealloc情况而确定是否crash程序,海阔天空,真相大白了吧!!!大笑三声哈哈哈.......

     

  • 相关阅读:
    算法总结之 两个链表生成相加链表
    算法总结之 复制含有随机指针节点的链表
    算法总结之 将单向链表按某值划分成左边小、中间相等、右边大的形式
    在PHP5.3以上版本运行ecshop和ecmall出现的问题及解决方案
    windows下配置nginx+php环境
    ecmall程序结构图与数据库表分析
    ecmall数据字典
    Ecmall二次开发-增删改查操作
    PHP7:10件事情你需要知道的
    PHP命名空间规则解析及高级功能3
  • 原文地址:https://www.cnblogs.com/huntaiji/p/3413621.html
Copyright © 2011-2022 走看看