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操作的一些理解,欢迎更多人加入讨论

  • 相关阅读:
    希望走过的路成为未来的基石
    第三次个人作业--用例图设计
    第二次结对作业
    第一次结对作业
    第二次个人编程作业
    第一次个人编程作业(更新至2020.02.07)
    Springboot vue 前后分离 跨域 Activiti6 工作流 集成代码生成器 shiro权限
    springcloud 项目源码 微服务 分布式 Activiti6 工作流 vue.js html 跨域 前后分离
    spring cloud springboot 框架源码 activiti工作流 前后分离 集成代码生成器
    java代码生成器 快速开发平台 二次开发 外包项目利器 springmvc SSM后台框架源码
  • 原文地址:https://www.cnblogs.com/iOS-mt/p/4237142.html
Copyright © 2011-2022 走看看