在之前的一片文章中,我们介绍了数组操作对象的时候引用问题以及自动释放池的概念,今天我们继续来看一下引用计数中一个痛疼的问题:循环引用

关于循环引用的问题,这里就不做太多解释了,就是多个对象之间相互引用,形成环状。

来看一个具体的例子:Dog类和Person类之间相互引用

Dog.h

 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,readwrite) Person *person;  
17   
18 - (void)dealloc;  
19   
20 @end

Dog.m

 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

 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,readwrite) Dog *dog;  
16   
17 - (void)dealloc;  
18   
19 @end

Person.m

 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

 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中,垃圾回收器也会遇到这样的问题,所以就不采用引用计数法去管理对象了,而是另外的一种方式去管理。

posted on 2015-01-03 14:39  I.L.L  阅读(290)  评论(0编辑  收藏  举报