zoukankan      html  css  js  c++  java
  • Objective-C中release和nil的关系

     

    (iphone/ipad)浅谈Objective-C中release和nil的关系

    分类: iPhone/iPad开发技术

    注意到经常有一个这样的问题:某指针对象先release后=nil,这里后跟个=nil有什么作用?不写行不行?

    简单一点说是,release是用来释放内存,nil是将对象指针设为null,nil本身对内存没什么影响,但他处理指针,尤其是避免野指针倒是很有必要。

    举一个例子:

    NSString *str=[[NSString alloc] init];

    当我不需要str时

    执行[str release];

    str 的retain值减1,但是如果当前retain值>0,却紧随其后加一句str=nil;那么这时[str retainCount]应该为0,因为[nil retainCount]==0;但这时很明显存在内存泄露。

    所以一个很好的写作习惯是:

    当对象的retainCount==1时,写完[str release];后接着写上str=nil;       这样,当在后面的代码再次调用str相关的方法属性,也不会报错,因为之前已经将str设置为空指针,再调用str的方法也会被认为是null,不会真正调用,更不会报错。

    例如下列代码:(以下所有代码段都已经过实际操作验证)

    1. UIView *view1=[[UIView alloc] init];  
    2.     UIView *view2=[view1 retain];  
    3.     int i=[view1 retainCount];  
    4.     NSLog(@"i:%d",i);  
    5.     [view1 release];  
    6.     view1=nil;  
    7.     [view1 addSubview:view2];  

    整个程序运行,是不会crash的。但是存在内存泄露。

    但是,现在又有另外一个问题,请看下列代码:

    1. UIView *view1=[[UIView alloc] init];  
    2.     UIView *view2=[view1 retain];  
    3.     int i=[view1 retainCount];  
    4.     NSLog(@"i:%d",i);  
    5.     [view1 release];  
    6.     view1=nil;  
    7.     [view1 addSubview:view2];  
    8.     i=[view1 retainCount];  
    9.     NSLog(@"i:%d",i);  
    10.     i=[view2 retainCount];  
    11.     NSLog(@"i:%d",i);  
    12.     [view2 release];  
    13.     i=[view2 retainCount];  
    14.     NSLog(@"i:%d",i);  

    请问终端输出的log应该是什么?

    第一个i=2,没问题,因为view1 init了一次,retain了1次,retain值为2。

    第二个i=0,根据上面所讲的推断,也没问题,因为之前view1=nil,空指针的retainCount值为0。

    第三个i=1,也没什么问题,因为view2是一个被赋了值的新指针,它不同于指针view1,二者是2个独立的指针,而且,view2还被赋了值分配了内存地址。

    但是,第四个i呢?i=?

    答案是i=1。为什么会这样?下面是真实输出结果:

    1. 2011-12-09 01:17:07.364 ReleaseNildemo[19115:f803] i:2  
    2. 2011-12-09 01:17:07.365 ReleaseNildemo[19115:f803] i:0  
    3. 2011-12-09 01:17:07.366 ReleaseNildemo[19115:f803] i:1  
    4. 2011-12-09 01:17:07.367 ReleaseNildemo[19115:f803] i:1  

    为什么会这样?按推理说,程序执行到输出这句应该crash才对,我运行了好几遍,确实没有出现。晚上在网上和其他程序员讨论这个问题,有人运行的情况是“有时候会crash,有时候不会。断点的话不会crash”,最后大家讨论的话题开始变成“系统是先输出还是先回收?”,更有甚者,有人输出了一下内存地址,发现是view2 release前后输出的是同一个内存地址,说明,这个东西内存虽然释放了,但是系统还没来得及回收。

    有时候crash,原因是你向一块未申请的内存发送了一条消息,最终成了系统回收速度问题了,所以,个人认为,以后碰到类似这种问题,干脆手动init,release,至少这样能很快释放,更便于清楚当前对象的内存情况。

    以上是我对release nil操作的一些理解,欢迎更多人加入讨论

  • 相关阅读:
    鼠标移入图片放大效果
    搜索框
    将下拉菜单放入input框中
    轮播图2
    V-demo item.vue
    v-demo1 List.vue
    v-demo1 add.vue
    v-demo1 app.vue
    3D轮播图
    封装代码
  • 原文地址:https://www.cnblogs.com/iOS-mt/p/4237142.html
Copyright © 2011-2022 走看看