【发布时间】: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