弱属性未设置为零

时间:2013-07-30 00:31:17

标签: objective-c memory-management automatic-ref-counting

我在UIViewController上定义了以下属性:

@property (nonatomic, strong) UIButton *strongButton;
@property (nonatomic, weak) UIButton *weakButton;

这些属性不是通过Interface Builder设置的(即只要我没有在代码中明确设置它们,它们将始终保持为零)。

我还在UIButton上添加了一个类别,以确切知道它何时被解除分配:

@implementation UIButton (test)
- (void)dealloc { NSLog(@"Dealloc called."); }
@end

我在UIViewController的viewDidLoad中有以下代码:

self.strongButton = [[UIButton alloc] init];
self.weakButton = self.strongButton;
NSAssert(self.weakButton != nil, @"A: Weak button should not be nil.");
NSLog(@"Setting to nil");
self.strongButton = nil;
NSLog(@"Done setting to nil");
NSAssert(self.weakButton == nil, @"B: Weak button should be nil.");

当我运行该代码时,在第二个断言(B)上失败。日志显示:

  • 设置为nil
  • 完成设置为nil
  • * 断言失败 - [ViewController viewDidLoad]
  • * 由于未捕获的异常'NSInternalInconsistencyException'而终止应用,原因:'B:弱按钮应为零。'

然而,当我评论第一个断言时:

self.strongButton = [[UIButton alloc] init];
self.weakButton = self.strongButton;
//NSAssert(self.weakButton != nil, @"A: Weak button should not be nil.");
NSLog(@"Setting to nil");
self.strongButton = nil;
NSLog(@"Done setting to nil");
NSAssert(self.weakButton == nil, @"B: Weak button should be nil.");

代码在日志中正常运行:

  • 设置为nil
  • Dealloc打来电话。
  • 完成设置为nil

注意在第一个场景中如何在适当的时间调用dealloc。

为什么第一个NSAssert会导致这种奇怪的行为?这是一个错误还是我做错了什么?

(我在iOS 6.1上)

1 个答案:

答案 0 :(得分:7)

读取弱变量可能会导致指向对象被保留并自动释放。然后,对象将保持活动状态,至少与当前自动释放池一样长。

在您的情况下,您的第一个NSAssert()读取弱变量。按钮对象被保留并自动释放。设置self.strongButton=nil不会导致按钮被释放,因为它在自动释放池中仍然存在,因此弱变量不会变为零。

当您注释掉NSAssert()时,弱变量不再被读取,因此该按钮不会被保留并自动释放,因此当您设置self.strongButton=nil时它确实会死亡。