我理解的objective-C内存管理

    我开始学习iOS的时候,已经有ARC这个东西了,因此一开始就是在ARC的环境下学习,虽然对于内存管理有了解,但并没认真去处理这方面的问题。工做中的项目是之前开始开发,使用的是非ARC,并且项目已经初步成型,很差改为ARC,因此我又回头去研究内存管理。开始时很晕,不知那些地方改retain、那些地方该release,不事后来清楚了 许多,并且感受挺喜欢这些东西,感受对于程序的运行对了一个角度的认识,以为很不错。之后新建项目,估计不多会不用ARC,只是以为内存管理仍是挺有意思的,并且是本身用心研究了的,就总结下。json

    一、结构:学习

   从对象的角度来看整个程序,是一个嵌套的结构,首先是一个A,这个A的构建运行过程当中又会用到许多其余的对象,而其余的对象再又会用到一些其余的对象,其实很像json的结构。为何要先这样去看程序呢?这样能够把整个程序当作是一个对象包含了许多其余对象的结构,这样内存管理就能够分解为两部分:(1)须要释放的对象释放掉  (2)一个对象释放的时候,它所用到得对象都改被释放(除了某些还被其余对象使用的对象)spa

    举例说就是push到一个ViewController,而后再从那个ViewController返回,那么这个viewController会释放,这通常都不会出错,可是这个Viewcontroller的成员变量都释放了吗?这个ViewController方法中构建的临时对象都释放了吗?而后你可能在这个viewContrller里面使用了一个自定义的对象,假设为pruductCell,那么当你把改释放这个对象的地方都处理好了,就能够再去看看它的.m文件,是否它使用的对象也释放正确了。指针

    我以为从这样一个结构去检查挺好的。code

   二、一个对象释放的时候,它所用到得对象都改被释放(除了某些还被其余对象使用的对象):对象

    首先,对象的引用和释放要遵循:你retain的你要release,不是你retain的不要release(假设为准则1)内存

 一个对象(假设为A)使用到的其余对象,能够分为两类:一个是临时对象(假设为B),用完就能够释放;还一个是对象的属性、成员变量(假设为C),这个通常都会在对象A各个方法中被重复用到,这样就能够等到对象A被释放的时候再释放,也就是在A的dealloc方法里面释放。开发

    临时对象:rem

 这个很好处理,用完了就释放掉:字符串

UIView * subView = [[UIView alloc]initWithFrame:CGRectMake(30, 100, 150, 260)];
    [self.view addSubview:subView]; //addsubView会retain子视图
    [subView release];
这里说的释放不是值释放内存,是指释放掉对这个临时对象的拥有权,就是执行release。对于拥有权,个人理解是对象A对某个对象(假设为B)进行了retain(包括alloc、copy等),这样其它引用了这个对象的 对象(假设为C),只要遵循准则1,当对象C release了对象B以后,对象B又会回到以前的引用计数。这样只要对象A不release对象B,B的内存就永远不会释放。这就像对象A是拥有了对象B。

   而对临时对象release,这样当引用它的对象也release它以后,它就没有被任何对象拥有,内存就会被释放,这样恰好。例如这里,当subView被从self.view上面移除后,基本就是不须要用这个subView的时候,这时它内存被释放,恰好。

  由于临时变量构建在方法里,出了这个方法就这个指针就没了,就无法释放对它的全部权了,因此必须在方法结束前release。

  属性、成员变量:

  为了在对象(A)存在的整个过程当中,它的属性、成员变量都活着,必须不能release,不然可能会引用计数为0,从而致使下次用的时候它内存已经被释放了,从而程序崩溃:

_subView = [[UIView alloc]initWithFrame:CGRectMake(30, 100, 150, 260)];
    [self.view addSubview:_subView];
    [_subView release];
    
    [_subView removeFromSuperview]; 
    
    NSLog(@"%@",_subView); //程序崩溃
不是说成员变量就不释放,而是释放了,下次再用就没有了。而既然是成员变量、属性,那么就是会再多个方法里面用到的,甚至会被其余的类的对象使用,因此要保持它是“活的”。


 三、关于属性定义时的关键词retain、assign:

      使用属性定义变量时,自带set\get方法,若是在变量赋值的时候使用self.XXX = YYY来方式赋值,实际上是调用了set方法,而与内存管理有关的问题是:若是属性定义时使用retain,set方法是:

-(void )setXXX:(UIView *)XXX{
    [XXX retain];
    [_XXX release];
    _XXX = XXX;
}
对新值会retain,对旧值会release,从而使得对传入的YYY获取拥有权,保证在self使用它期间,它的内存永不会被释放掉。这也遵循准则1。而使用assign倒是简单赋值,没有retain\release的操做。

   若是属性是assign或者干脆没有使用self.XXX进行赋值,那么就不会retain赋值对象,那么:

UIView * view1 = [[UIView alloc]initWithFrame:CGRectMake(30, 100, 150, 260)];
    _XXX = view1;
    [view1 release];
这里不会崩溃,可是接下来_XXX就变成了僵尸指针了,它指向位置的内存被释放了,这也是assgin脆弱的地方,因此须要较长时间对某个对象的使用,最好使用retain,保证引用计数不会为0。

 四、关于autoRelease:

  首先类方法构建对象,返回值通常自带autoRelease,使用时注意下。

  为何要使用autoRelease,个人理解是延缓release。由于我构建的,因此我要释放,可是若是我release了,这个对象内存就被释放了,那不就白构建了吗?能够构建,而后把它给须要使用的地方,而后再释放。好比带放回值得方法:

-(NSString *)createString{
    NSString * str = [[NSString alloc]init];
    return str;
}
若是我在方法里面不释放,而后外面使用的时候遵循准则1,那么最后这个str的引用计数会保持在1,不会被释放,这样很成问题。可是若是释放了,那return的就是空值,没意义了。 autoRelease使用了,就能够return一个有意义的值,而后最后这个对象在自动释放池里能被释放,不用担忧内存泄露。

 五、特殊的方法和对象:

   addSubview会对添加进来的视图retain,NSMutableArray的adObject也会retain添加的对象,block会对里面使用到的变量所有retain,极可能形成循环引用,NStimer在没有释放的时候,会retain构建是指定的target,想要释放掉target,就须要先中止NSTimer。

   字符串常量不须要咱们管理内存。

相关文章
相关标签/搜索