为什么这段代码在ARC下会泄漏?(一个__weak实例变量)

3
我遇到了一个奇怪的内存泄漏问题。以下的Car类的对象永远不会被释放。
然而,如果我去掉实例变量_unsafe_self并在init方法内声明(和以前一样赋值)该变量,则泄漏消失了。
这是什么原因呢?我认为__weak应该是弱引用,无论是实例变量还是其他任何东西。
@interface Car : NSObject
@end

@implementation Car {
  id _obs;
  __weak Car *_unsafe_self;
}

- (id)init {
  if (!(self = [super init]))
    return nil;

  _unsafe_self = self;

  _obs = [[NSNotificationCenter defaultCenter]
          addObserverForName:NSWindowDidMoveNotification
          object:nil
          queue:[NSOperationQueue mainQueue]
          usingBlock:^(NSNotification *note) {
              NSLog(@"hello %@", _unsafe_self);
            }];

  return self;
}

- (void)dealloc {
  [[NSNotificationCenter defaultCenter] removeObserver:_obs];
}
@end
1个回答

9

_unsafe_selfself->_unsafe_self相同,因此在该块中。

_obs = [[NSNotificationCenter defaultCenter]
          addObserverForName:NSWindowDidMoveNotification
          object:nil
          queue:[NSOperationQueue mainQueue]
          usingBlock:^(NSNotification *note) {
              NSLog(@"hello %@", _unsafe_self);
            }];

在捕获self的同时,会导致一个保留循环(retain cycle),从而防止self被释放。

以下情况不会导致保留循环:

__weak Car *weakSelf = self;
_obs = [[NSNotificationCenter defaultCenter]
        addObserverForName:NSWindowDidMoveNotification
        object:nil
        queue:[NSOperationQueue mainQueue]
        usingBlock:^(NSNotification *note) {
            NSLog(@"hello %@", weakSelf);
        }];

使用属性self.unsafe_self会使代码更加明显,但已经有足够多的“属性 vs 实例变量”的问答了 :-)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接