OC学习篇之---循环引用问题

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

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

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

你可能感兴趣的:(学习)