我遇到一个破坏的指针,在指向对象释放后指向垃圾的问题。 objectA 是来自其他对象 objectB 的回调的委托。
objectA 经常被分配和发布(在我的应用程序中是一个菜单UI对象)。每次初始化 objectA 时,它都会初始化 objectB 并开始异步操作,然后通过id delegate属性回调 objectA 。
如何阻止我的指针:id委托破坏?
ObjA.m
-(void)dealloc{
[super dealloc];
}
+(id)init{
ObjA *objectA = [[ObjA alloc]init];
return objectA;
}
-(id)init{
if (self == [super init]){
ObjB *objectB = [ObjB initialiseWithDelegate:self];
}
return self;
}
-(void)callback:(id)arg{
//This callback is called from an asynchronous routine from objectB
}
-(void)terminate{
//This is called when I want to remove/release objectA
//Other logical termination code here
[self release];
}
ObjB.m
@synthesize delegate;
+(id)initialiseWithDelegate:(id)delegate{
ObjB *objectB = [[ObjB alloc]init];
[objectB setDelegate:delegate];
return objectB;
}
-(id)init{
if (self == [super init]){
[self beginAsynchronousOperation];
}
return self;
}
-(void)beginAsynchronousOperation{
//Do asynchronous stuff here
}
-(void)finishedAsynchronousOperation{
//Called when asynch operation is complete
if (self.delegate) [self.delegate callback:someargument]; //EXC error. Pointer broke
}
答案 0 :(得分:1)
这里简短的回答是,当你释放objectA时,你nil
出了objectB的delegate
属性。因为代理被分配,而不是保留(显式地阻止保留周期),如您所见,当“拥有”对象消失时,委托引用可以保持挂起。通常,objectA将保留对objectB的保留引用,并且在objectA的dealloc
期间,它将首先将objectB的delegate
设置为nil
,然后设置release
objectB。这样可以防止崩溃。当然,这假设(通常情况下)您不需要对异步完成执行任何操作。它还假设objectB在异步操作过程中可以安全地释放objectB。这通常适用于(例如)动画,但如果您正在构建自己的任务,则可能需要注意此处的生命周期。
有关此代码段的一些注意事项可能会有所帮助:
您的objectA在创建后实际上并未持有对objectB的引用。这意味着你无法排除代表。您应该在创建对象时保留对objectB的引用,以便您可以执行此操作。
您正在泄漏objectB。 ObjectA创建它(alloc,init),但随后删除引用,所以即使它完成了,似乎没有人负责释放它。再一次,持有它以便你可以释放它也将解决这个问题。
对象A上的-terminate
是一个反模式 - 一个对象永远不应该(只有一个例外:init
内的失败)在{{-release
上调用self
1}}。对象应由其所有者发布,该对象是最初创建 it 的人。
您的if (self == [super init])
模式通常使用一个等号写入,这意味着您既为结果指定了self
,又为nil
检查了{{1}}。这是一个可可的历史奇怪,可能在这里没什么区别,但值得指出。