0

我有一个非常标准的案例,为了简单起见,假设有 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 打印出对象)。但是,在进入 [self removeObserver:_delegate] 之后,_delegate 立即为零,我的意思是 param 从内部为零。

更新 如果我在 dealloc 中执行“po _delegate”,我可以看到对象,所以它不是零。但是一旦代码进入 [self removeObserver:_delegate],它的内部就是 nil,所以它不会作为参数传递给“removeObserver:”。但是,当我在调试时从“removeObserver:”返回到 dealloc 时,_delegate 不再为零。

4

1 回答 1

1

这大致是这里发生的事情:

  • MyController实例被释放时,它的实例变量_myModel被设置为nil,这会导致-[MyModel dealloc]被调用。
  • 此时,_delegate实例变量还没有nil,但访问 委托会返回nil,因为指向的对象正在被释放。

(有关更详细的分析,请参阅Weak property is set to nil in dealloc but property's ivar is not nil 。)

观察弱属性通常是危险的,因为模型无法控制何时释放该对象。

如果您只想拥有与手动引用计数相同的行为,您可以将delegate属性声明为assign而不是weak. 这意味着一个__unsafe_unretained 实例变量,可以解决您的问题。

于 2013-06-11T17:17:31.327 回答