[英]ARC: Dealloc releases delegate before I can remove it from observer list
我有一个标准的案例,为简单起见,假设有MyController及其MyModel。 这是MyModel的摘录:
@interface MyModel
@property (nonatomic, weak) id<ModelObserver> *delegate;
@end
@implementation MyModel
- (id)initWithDelegate:(id<ModelObserver>)delegate
{
self = [super init];
if (self) {
_delegate = delegate;
// Adds observer for model load and changes
[self addObserver:_delegate];
...
}
- (void)dealloc
{
// Remove delegates and progress indicator
[self removeObserver:_delegate];
@end
这是MyController的摘录
@interface MyController
@property (nonatomic, strong) MyModel *_myModel;
@end
@implementation MyController
- (void)commonInit
{
_myModel = [[MyModel alloc] initWithDelegate:self];
}
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
[self commonInit];
}
return self;
}
@end
MyModel具有类型为id(指向MyController)的委托。 MyController具有强大的ivar _myModel。 MyController创建模型,并将自己作为委托传递给alloc。 MyModel扩展了MyBaseModel,并向观察者列表添加了一个委托(MyController),并获得有关列表模型更改的通知。 问题是,观察者MyController在[self removeObserver:_delegate]之前被释放。 能够将其从观察者列表中删除,因此有时稍后我会崩溃。
已经进行调试,并且在“ [self removeObserver:_delegate];”上停止执行时 MyController仍然存在(po _delegate打印出对象)。 但是,_delegate在进入[self removeObserver:_delegate]之后就为零,我的意思是param从内部为零。
更新如果我在dealloc中执行“ po _delegate”,我可以看到对象,所以它不是nil。 但是,一旦代码进入[self removeObserver:_delegate],它就为零,因此它不会作为参数传递给“ removeObserver:”。 但是,当我在调试时从“ removeObserver:”返回以取消分配时,_delegate不再为nil。
这大致是这里发生的情况:
MyController
实例后,其实例变量_myModel
设置为nil
,这将导致调用-[MyModel dealloc]
。 _delegate
实例变量尚未为nil
,但是访问委托返回的结果为nil
因为指向对象的对象正在释放中。 (有关更详细的分析,请参阅在dealloc中弱属性设置为nil,但属性的ivar设置为nil 。)
观察弱属性通常很危险,因为模型无法控制何时释放该对象。
如果只想拥有与手动引用计数相同的行为,则可以将delegate
属性声明为assign
而不是weak
。 这意味着__unsafe_unretained
实例变量,可以解决您的问题。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.