------- <a href="http://www.itheima.com" target="blank">android培训</a>、<a href="http://www.itheima.com" target="blank">java培训</a>、期待与您交流! ----------
循环retain问题即A对象retainB对象,B对象同时也retainA对象。
例
Book
#import <Foundation/Foundation.h>
@class Person;
@interface Book : NSObject
@property(nonatomic,retain)Person *author;
@end
#import "Book.h"
@implementation Book
- (void)dealloc
{
[_author release];
NSLog(@"Book----->dealloc");
[super dealloc];
}
@end
Person
#import <Foundation/Foundation.h>
@class Book;
@interface Person : NSObject
@property(nonatomic,retain)Book *bigBook;
@end
#import "Person.h"
@implementation Person
- (void)dealloc
{
[_bigBook release];
NSLog(@"Person----->dealloc");
[super dealloc];
}
@end
main
int main(int argc, const char * argv[]) {
@autoreleasepool {
Person *p = [Person new];
Book *b = [Book new];
p.bigBook = b;
b.author =p;
[p release];
[b release];
}
return 0;
}
上面代码看似很正确,p->new然后p->release,b->new然后b->release,并且都重写了dealloc方法,也再释放自己的同时释放了自己的实例对象。
但程序运行毫无结果,即无法打印出Book----->dealloc,也无法打印出Person----->dealloc。
在main代码调用release之前加行代码
<span style="font-size:14px;">NSLog(@"%ld\t%ld",p.retainCount,b.retainCount);</span>
打印发现p和b的计数器都是2,这是因为p和b的set方法都会将传入的对象retain一次,导致p和b的计数器都变为2,而在main中只分别调用了一次release,这样p和b的计数器都是1,所以他都没有调用dealloc方法。
解决方法一是再在main函数里用 p或者b调用一次release,不过这种方法可能会由于顺序或者其他原因导致报错或警告,并不安全。
另一种解决方法是将Person类的retain换成assign,注意换成assign 的那个类(Person类)的dealloc方法就不必再进行release了,因为assign并不会在set方法中对传入的对象进行retain,所以被传入对象的计数器不会+1,这样在程序进行到
[p release];
[b release];
的时候p的计数器为2,b的计数器为1,[p release]之后计数器变为1,[b release]之后b的计数器为0,b摧毁,b调用dealloc方法,dealloc方法会进行 [p release]操作,p的计数器为0,p摧毁,p调用dealloc方法。程序到此正常结束。