【问题标题】:Weak property not being set to nil [duplicate]弱属性未设置为零[重复]
【发布时间】:2013-07-30 00:31:16
【问题描述】:

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

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

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

我还在 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) 上失败。日志显示:

  • 设置为零
  • 完成设置为零
  • * -[ViewController viewDidLoad] 中的断言失败
  • * 由于未捕获的异常“NSInternalInconsistencyException”而终止应用程序,原因:“B: Weak button should be nil.”

但是,当我注释掉第一个断言时:

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.");

代码在日志中运行良好:

  • 设置为零
  • 调用了Dealloc。
  • 完成设置为零

注意在第一个场景中,dealloc 没有在适当的时间被调用。

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

(我使用的是 iOS 6.1)

【问题讨论】:

  • 我可能是错的(不是这方面的专家),但我认为 ARC 在自动释放池耗尽之前不会清理弱指针。所以self.weakButton 在当前运行循环结束之前不会是nil
  • 如果您为第二个断言创建了第二个按钮,我敢打赌它会起作用。
  • @AaronBrager:如果我将第二个断言移至viewDidAppear,它可以正常工作。但是,我认为这并不能解释为什么第二种情况确实有效。
  • weak 与自动释放池无关。您可能会想到,如果一个强引用对象被自动释放,那么该强引用不会消失,直到自动释放池在耗尽时将其删除。
  • 当你使用'assign'而不是'weak'时,你会得到相同的行为吗?我问的原因是Apple说“对于声明的属性,你应该使用assign而不是weak;”在过渡到 ARC 发行说明中。顺便说一句,你的问题对我来说听起来像是一个错误。

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


【解决方案1】:

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

在您的情况下,您的第一个 NSAssert() 读取弱变量。按钮对象被保留并自动释放。设置self.strongButton=nil 不会导致按钮被释放,因为它在自动释放池中还活着,所以weak变量不会变成nil。

当你注释掉NSAssert()时,weak变量不再被读取,所以按钮不会被保留和自动释放,所以当你设置self.strongButton=nil时它确实死了。

【讨论】:

猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2010-12-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-12-16
  • 2016-02-20
相关资源
最近更新 更多