• OC中对象元素的引用计数 自动释放池的相关概念


    OC中数组对象在是如何处理对象元素的引用计数问题的,同时介绍一下自动释放池的相关概念


    一、数组对象是如何处理对象元素的引用计数问题
    [objc]  view plaincopy
    1. //  
    2. //  main.m  
    3. //  26_NSArrayMemeryManager  
    4. //  
    5. //  Created by jiangwei on 14-10-12.  
    6. //  Copyright (c) 2014年 jiangwei. All rights reserved.  
    7. //  
    8.   
    9. #import <Foundation/Foundation.h>  
    10.   
    11. #import "Dog.h"  
    12.   
    13. int main(int argc, const charchar * argv[]) {  
    14.       
    15.     Dog *dog1 = [[Dog alloc] init];  
    16.     Dog *dog2 = [[Dog alloc] init];  
    17.       
    18.     NSMutableArray *array = [[NSMutableArray alloc] init];  
    19.       
    20.     //数组会对每一个元素retain  
    21.     [array addObject:dog1]; //dog1计数=2  
    22.     [array addObject:dog2]; //dog2计数=2  
    23.       
    24.     [dog1 release];  
    25.     [dog2 release];  
    26.       
    27.     //当数组销毁的时候,会将所有的元素release  
    28.     [array release];//数组销毁  
    29.       
    30.     //当数组移除所有的元素的时候,会讲所有的元素release  
    31.     [array removeAllObjects];  
    32.       
    33.     return 0;  
    34. }  
    我们定义了Dog类,然后定义了NSMutableArray数组存放两个Dog对象,OC中在将对象放到数组中的时候,会自动调用retain方法,当数组对象本身被销毁的时候,会调用所有元素的release方法,当移除数组中所有的元素的时候,会调用元素的release方法


    二、自动释放池的概念
    [objc]  view plaincopy
    1. //  
    2. //  main.m  
    3. //  27_AutoReleasePool  
    4. //  
    5. //  Created by jiangwei on 14-10-13.  
    6. //  Copyright (c) 2014年 jiangwei. All rights reserved.  
    7. //  
    8.   
    9. #import <Foundation/Foundation.h>  
    10.   
    11. #import "Dog.h"  
    12.   
    13. int main(int argc, const charchar * argv[]) {  
    14.       
    15.     /* 
    16.     //创建一个自动释放池 
    17.     //有作用域的问题,在{}中定义的东西外部是不能访问的,这点和NSAutoreleasePool有区别的 
    18.     @autoreleasepool {//等价于[[NSAutoreleasePool alloc] init] 
    19.         
    20.         Dog *dog2 = [[Dog alloc] init]; 
    21.         [dog2 retain]; 
    22.          
    23.     }//等价于[pool release] 
    24.      
    25.     //创建一个自动释放池 
    26.     NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 
    27.      
    28.     Dog *dog1 = [[Dog alloc] init];//计数:1 
    29.      
    30.     //将dog1对象加入到自动释放池中,却别于之前的release方法 
    31.     //加入到自动释放池中之后,不是代表我们不需要管理引用了,只是自动释放池自动会调用一次release 
    32.     //当自动释放池销毁的时候,释放池会对池中每一个对象调用一次release 
    33.     [dog1 autorelease]; 
    34.     NSLog(@"dog1计数:%ld",dog1.retainCount); 
    35.      
    36.     //销毁自动释放池 
    37.     //这时候会调用dog1的release方法,dog1对象就被销毁了 
    38.     [pool release]; 
    39.     */  
    40.       
    41.     //自动释放池的嵌套  
    42.     NSAutoreleasePool *pool1 = [[NSAutoreleasePool alloc] init];  
    43.       
    44.     //添加我们的代码  
    45.     //dog1放到了pool1中  
    46.     Dog *dog1 = [[Dog alloc] init];  
    47.     [dog1 autorelease];  
    48.       
    49.     //自动释放池的嵌套  
    50.     NSAutoreleasePool *pool2 = [[NSAutoreleasePool alloc] init];  
    51.       
    52.     //dog2放到了pool2中  
    53.     Dog *dog2 = [[Dog alloc] init];  
    54.     [dog2 autorelease];  
    55.       
    56.     //pool2销毁了  
    57.     [pool2 autorelease];  
    58.       
    59.     //pool1销毁了  
    60.     [pool1 release];  
    61.       
    62.       
    63.     //下面的代码就是有问题的  
    64.     //[person setDog:[[Dog alloc] init];  
    65.     //正确的写法  
    66.     //Dog *dogs = [[[Dog alloc] init] autorelease];  
    67.       
    68.       
    69.        
    70.     return 0;  
    71. }  
    我们在之前的文章中,定义一个对象的时候都会产生一个自动释放池,然后在释放池中编写我们的代码,自动释放池是系统提供的一种帮助我们去管理对象的引用计数问题。但是有时候代码必须在{...}中编写,这样的话就会产生作用域的问题,就是在{...}中定义的变量,在{...}外面不能使用。所以OC中就有了另外的一种方式:NSAutoreleasePool这个类
    这种自动释放池可以实现嵌套
    NSAutoreleasePool *pool1 = [[NSAutoreleasePool alloc] init];
    //write code...
    //pool1销毁了
    [pool1 release];
    上面的代码就相当于建立了一个自动释放池pool1,但是在这个中间的代码,如果要加入到这个池中,必须调用autorelease方法:
    [java]  view plaincopy
    1. //dog1放到了pool1中  
    2. Dog *dog1 = [[Dog alloc] init];  
    3. [dog1 autorelease];  
    而且,这样定义一个池子还可以嵌套使用,直接看上面的例子代码,这样这个自动释放池我们就可以控制了。比系统提供的自动释放池可操作的地方很多
    下面就直接对比一下:
    NSAutoreleasePool *pool1 = [[NSAutoreleasePool alloc] init];
    这行代码就相当于系统自动释放池的 {
    [pool1 release];
    这行代码就相当于系统自动释放池的 }
    这样就好理解了吧

    总结
    这一篇文章主要介绍了OC中数组对象操作元素对象的时候需要处理的引用问题,以及我们可以自定义一个自动释放池,这种方式比系统提供的自动释放池方便,可操作性强。



    OC中引用计数中一个痛疼的问题:循环引用.note
     
    引用计数中一个痛疼的问题:循环引用
    关于循环引用的问题,这里就不做太多解释了,就是多个对象之间相互引用,形成环状。
    来看一个具体的例子:
    Dog类和Person类之间相互引用


    Dog.h
    [objc]  view plaincopy
    1. //  
    2. //  Dog.h  
    3. //  29_CyclePointer  
    4. //  
    5. //  Created by jiangwei on 14-10-13.  
    6. //  Copyright (c) 2014年 jiangwei. All rights reserved.  
    7. //  
    8.   
    9. #import <Foundation/Foundation.h>  
    10.   
    11. #import "Person.h"  
    12.   
    13. @interface Dog : NSObject  
    14.   
    15. //这里不用retain,如果使用retain的话,会形成循环引用  
    16. @property(nonatomic,assign,readwritePerson *person;  
    17.   
    18. - (void)dealloc;  
    19.   
    20. @end  


    Dog.m
    [objc]  view plaincopy
    1. //  
    2. //  Dog.m  
    3. //  29_CyclePointer  
    4. //  
    5. //  Created by jiangwei on 14-10-13.  
    6. //  Copyright (c) 2014年 jiangwei. All rights reserved.  
    7. //  
    8.   
    9. #import "Dog.h"  
    10.   
    11. @implementation Dog  
    12.   
    13. - (void)dealloc{  
    14.     //[_person release];  
    15.     NSLog(@"dog dealloc");  
    16.     [super dealloc];  
    17. }  
    18.   
    19. @end  
    Dog类中有一个Person类型的属性


    Person.h
    [objc]  view plaincopy
    1. //  
    2. //  Person.h  
    3. //  29_CyclePointer  
    4. //  
    5. //  Created by jiangwei on 14-10-13.  
    6. //  Copyright (c) 2014年 jiangwei. All rights reserved.  
    7. //  
    8.   
    9. #import <Foundation/Foundation.h>  
    10.   
    11. @class Dog;  
    12.   
    13. @interface Person : NSObject  
    14.   
    15. @property(nonatomic,retain,readwriteDog *dog;  
    16.   
    17. - (void)dealloc;  
    18.   
    19. @end  

    Person.m
    [objc]  view plaincopy
    1. //  
    2. //  Person.m  
    3. //  29_CyclePointer  
    4. //  
    5. //  Created by jiangwei on 14-10-13.  
    6. //  Copyright (c) 2014年 jiangwei. All rights reserved.  
    7. //  
    8.   
    9. #import "Person.h"  
    10.   
    11. #import "Dog.h"  
    12.   
    13. @implementation Person  
    14.   
    15. - (void)dealloc{  
    16.     [_dog release];  
    17.     NSLog(@"Person dealloc");  
    18.     [super dealloc];  
    19. }  
    20.   
    21. @end  
    Person类中有Dog类型的属性


    看一下测试代码
    main.m
    [objc]  view plaincopy
    1. //  
    2. //  main.m  
    3. //  29_CyclePointer  
    4. //  
    5. //  Created by jiangwei on 14-10-13.  
    6. //  Copyright (c) 2014年 jiangwei. All rights reserved.  
    7. //  
    8.   
    9. #import <Foundation/Foundation.h>  
    10.   
    11. #import "Dog.h"  
    12. #import "Person.h"  
    13.   
    14. //循环引用  
    15. //是一个很麻烦的一件事,完全靠经验  
    16. int main(int argc, const charchar * argv[]) {  
    17.       
    18.     Person *p = [[Person alloc] init];  
    19.     Dog *dog = [[Dog alloc] init];  
    20.       
    21.     [p setDog:dog];//dog计数:2  
    22.       
    23.     [dog setPerson:p];//person计数:2  
    24.       
    25.     [p release]; //person计数:1  
    26.     [dog release];//dog计数:1  
    27.       
    28.     //没有释放的原因是dealloc方法中没有被执行,里面的释放代码也就没执行了,dog和person各自在等待,形成环状了  
    29.     //解决版本就是切断他们之间的联系  
    30.     //@property中不使用retain,使用assgin  
    31.       
    32.     NSLog(@"is over");  
    33.       
    34.     return 0;  
    35. }  
    我们分别定义了一个Person对象和Dog对象,然后相互引用了,但是当我们调用他们的release方法的时候,这两个对象并没有被释放
    原因很简单:
    person和dog的相互引用了,当执行release方法的时候引用计数都还是1,所以就不会调用dealloc方法了
    dealloc方法中没有被执行,里面的释放代码也就没执行了,dog和person各自在等待,形成环状了

    解决的办法是:
    切断他们之间的联系
    在一方中定义属性的时候,@property中不使用retain,使用assgin
    同时在dealloc方法中不再调用release方法了
    上面的例子中,我们可以看到Dog类中就是使用assgin

    总结
    循环引用是对象销毁的时候遇到的最大的一个问题,在java中,垃圾回收器也会遇到这样的问题,所以就不采用引用计数法去管理对象了,而是另外的一种方式去管理,可以参考:http://blog.csdn.net/jiangwei0910410003/article/details/40709457
  • 相关阅读:
    【转】Linux中的特殊权限粘滞位(sticky bit)详解
    【转】Spark实现行列转换pivot和unpivot
    Pyspark 使用 Spark Udf 的一些经验
    CDH 集群机器上部署 Jupyter notebook 使用 Pyspark 读取 Hive 数据库
    Pyspark-SQL 官方 API 的一些梳理(上)
    Kafka-python 客户端导致的 cpu 使用过高,且无法消费消息的问题
    如何创建和管理 MySQL 相关权限
    CDH Yarn 调度资源指南
    Sqoop export(Hive to MySQL) 的一些 reference
    vue2.x学习笔记(二十七)
  • 原文地址:https://www.cnblogs.com/GhostKZShadow/p/5105399.html
Copyright © 2020-2023  润新知