您的位置:首页 > 移动开发 > Objective-C

Objective-c 循环引用

2015-09-05 20:32 555 查看
Objective-c 循环引用
OC内存管理中有一种特殊的对象管理,那就是循环引用。循环引用即是类A中有类B作为成员变量,同时类B中又同时有类A作为成员变量。这种情况下,引用计数器需要特殊的处理。下面分别介绍非ARC情况下的循环引用和ARC情况下的循环引用。

一、非ARC情况下的循环引用,Person类中包含Card类,Card类中包含Person类。

1、Person类中对card类进行retain ,所以需要进行release。

#import <Foundation/Foundation.h>
@class Card;//因为需要用到,所以声明
@interface Person : NSObject
//属性是一个Card类, 对象被引用,所以用retain
@property (nonatomic,retain)Card *card;
@end


#import "Person.h"
#import "Card.h"//.m中需要知道Card类的具体实现
@implementation Person
- (void)dealloc
{
NSLog(@"Person被销毁了");
[_card release];//有retain,所以需要release
[super dealloc];
}
@end
2、Card类中,为了Person对象的retainCount 不改变,所以使用assign 进行直接赋值

#import <Foundation/Foundation.h>
@class Person;
@interface Card : NSObject
// 使用assign,是Person对象的retainCount不 +1
@property (nonatomic,assign)Person *person;
@end


#import "Card.h"
@implementation Card
- (void)dealloc
{
NSLog(@"Car被销毁了");
//不对_person进行release,因为使用的是assign
[super dealloc];
}
@end
3、main函数中,写清楚了 每一个对象的retainCount的变化:

#import <Foundation/Foundation.h>
#import "Person.h"
#import "Card.h"
int main(int argc, const char * argv[]) {
@autoreleasepool {
Person *p = [[Person alloc] init];//p的retainCount 1
Card *c = [[Card alloc] init];//c的retainCount 1

p.card = c;//c的retainCount 1+1=2
c.person = p;//p的retainCount 1 不变
[c release];//c的retainCount 2-1=1
[p release];//p和c的retainCount 都是 0
}
return 0;
}
小结:在非ARC中,两个类之间进行循环引用,应该一端 使用retain,另一端使用 assign。因为,计数器只要实现一端引用是+1,另一端中不需要+1 ,所以使用assign 。

二、ARC情况下的循环引用
为了便于对比,还是使用 Person类和Card类的循环引用
1、Person类中对card类指针定义为strong指针

#import <Foundation/Foundation.h>
@class Card;
@interface Person : NSObject
@property (nonatomic,strong)Card *card;
@end


#import "Person.h"
#import "Card.h"
@implementation Person
- (void)dealloc
{
NSLog(@"Person被销毁了");
//[_card release];不需要手动释放了
//[super dealloc];//ARC下不能调用[super dealloc]
}
@end


2、Card类中,为了保持指向Person对象的strong指针数量不变,所以使用weak

#import <Foundation/Foundation.h>
@class Person;
@interface Card : NSObject
@property (nonatomic,weak)Person *person;
@end


#import "Card.h"
@implementation Card
- (void)dealloc
{
NSLog(@"Car被销毁了");
//ARC情况下可以重写dealloc,但是不能调用[super dealloc];
}
@end


3、main函数中,写清楚了 每一个对象的strong指针数量的变化:

#import <Foundation/Foundation.h>
#import "Person.h"
#import "Card.h"
int main(int argc, const char * argv[]) {
@autoreleasepool {
Person *p = [[Person alloc] init];//p 是1条强指针,指向Person 空间

Card *c = [[Card alloc] init];//p 是1条强指针,指向Card空间

p.card = c;//p.card 也是一条强指针指向Card空间,2条

c.person = p;//c.person 是一条weak指针, 所以Person空间强指针还是 1
}
//自动释放池,结束会向p和c 各自发送一条 release消息
// 最后相当于手动管理中对象的retainCount都会变为0;
return 0;
}

小结:在ARC中,两个类之间进行循环引用,应该一端 使用strong,另一端使用 weak。因为,在ARC条件下,系统判断对象是否销毁的标准是:指向对象空间的strong指针的总数是否为0 ,如果归零,代表对象已经销毁。 对象是否销毁与 weak指针没有任何关系。如果,weak指针指向的对象空间销毁了,系统会自动是 weak指针归nil 。

说到底,ARC情况下的 对象拥有的strong指针的个数 等价于 非ARC情况下的 retainCount。只要记住这一条,两者就很容易辨别了。
下面附上内存图,便于理解,实线代表强指针,虚线代表弱指针。

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: