在之前的一片文章中,我们介绍了数组操作对象的时候引用问题以及自动释放池的概念,今天我们继续来看一下引用计数中一个痛疼的问题:循环引用
关于循环引用的问题,这里就不做太多解释了,就是多个对象之间相互引用,形成环状。
来看一个具体的例子: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中,垃圾回收器也会遇到这样的问题,所以就不采用引用计数法去管理对象了,而是另外的一种方式去管理。