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

时间: 2024-09-29 04:21:51

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

OC学习篇之---数组对象的引用计数问题和自动释放池的概念

之前一片文章中我们介绍了OC中的两个关键字@property和@synthesize的使用的使用: http://blog.csdn.net/jiangwei0910410003/article/details/41925967 今天我们来看一下OC中数组对象在是如何处理对象元素的引用计数问题的,同时介绍一下自动释放池的相关概念 一.数组对象是如何处理对象元素的引用计数问题 // // main.m // 26_NSArrayMemeryManager // // Created by jian

(转载)OC学习篇之---数组对象的引用计数问题和自动释放池的概念

之前一片文章中我们介绍了OC中的两个关键字 @property 和 @synthesize 的使用的使用,今天我们来看一下OC中数组对象在是如何处理对象元素的引用计数问题的,同时介绍一下自动释放池的相关概念 一.数组对象是如何处理对象元素的引用计数问题 1 // 2 // main.m 3 // 26_NSArrayMemeryManager 4 // 5 // Created by jiangwei on 14-10-12. 6 // Copyright (c) 2014年 jiangwei.

cocos2D-x 3.5 引擎解析之--引用计数(Ref),自动释放池(PoolManager),自动释放池管理器( AutoreleasePool)

#include <CCRef.h> Ref is used for reference count manangement. If a classinherits from Ref. Class Ref 为引用计数类,用来管理对象的引用计数.这样就不会出现还有指针保持指向该对象,当使用该指针操作时,如果指向的对象被销毁就会出现程序异常. class CC_DLL Ref { public: void retain();//增加引用计数一次 void release();//减少引用计数一次,

OC基础(十三)autorelease自动释放池

autorelease 自动释放池 autorelease是一种支持引用计数的内存管理方式,只要给对象发送一条autorelease消息,会将对象放到一个自动释放池中,当自动释放池被销毁时,会对池子里面的所有对象做一次release操作 优点:不用再关心对象释放的时间,不用再关心什么时候调用release 原理:autorelease实际上只是把对release的调用延迟了,对于每一个autorelease,系统只是把该 Object放入了当前的autorelease pool中,当该pool被

黑马程序员-OC学习笔记之autorelease与自动释放池

---------------------- IOS开发.Android培训.期待与您交流! ---------------------- 一.autorelease autorelease与release相似,是OC中的一个对象方法.这两个方法都能把对象的引用计数器减1,但是release是一个精确的减1,对对象的操作只能在release之前进行,如果是在之后,就会出现野指针错误:而autorelease是一个不精确的引用计数器减1,当给对象发送autorelease消息时,对象就会被放到自动

OC基础笔记——自动释放池

autorelease:延长对象生命周期 把对象放到离自己最近那个自动释放池中 当自动释放池销毁的时候,它会把放在其中所有对象进行一次release的操作 它和对象在哪里创建没有关系 自动释放池的原理: 1.系统中存在一个自动释放池栈, 当遇到 @autoreleasepool { 把这个自动释放池压入栈中 2.但遇到与之对应 } 自动释放池,出栈,它出栈的时候,会对池中所有对象进行一次release操作 3.自动释放池栈中,只有栈顶自动释放池是活动的,其他的都在休眠 4.当你调用autorel

黑马程序员--Objective-C之--自动释放池的概念以及使用

今天我们来看一下OC中数组对象在是如何处理对象元素的引用计数问题的,同时介绍一下自动释放池的相关概念 一.数组对象是如何处理对象元素的引用计数问题 // // main.m // 26_NSArrayMemeryManager // // Created by waterfoxjie on 15-03-29. // Copyright (c) 2015年 waterfoxjie. All rights reserved. // #import <Foundation/Foundation.h>

objective-C 的内存管理之-自动释放池(autorelease pool)

如果一个对象的生命周期显而易见,很容易就知道什么时候该new一个对象,什么时候不再需要使用,这种情况下,直接用手动的retain和release来判定其生死足矣.但是有些时候,想知道某个对象在什么时候不再使用并不那么容易.如果下面的代码,看上去非常简单: Sample.h类接口部分 #import @interface Sample : NSObject { } -(NSString*) toString; @end Sample.m 类实现部分 #import "Sample.h"

第34条:以“自动释放池块”降低内存峰值

本条要点:(作者总结) Objective-C 对象的生命期取决于其引用计数(参见第29条).在 Objective-C 的引用计数架构中,有一项特性叫做"自动释放池"(autorelease pool).释放对象有两种方式:一种是调用 release 方法,使其保留计数立即递减:另一种是调用 autorelease 方法,将其加入 "自动释放池"中.自动释放池用于存放那些需要稍后某个时刻释放的对象.清空(drain)自动释放池时,系统会向其中的对象发送 relea