This question already has an answer here:
这个问题已经有了答案:
- Why isn’t my weak reference cleared right after the strong ones are gone? 4 answers
- 为什么我的弱引用不能在强引用消失后立即清除?4答案
I have the following properties defined on a UIViewController:
我在UIViewController上定义了以下属性:
@property (nonatomic, strong) UIButton *strongButton;
@property (nonatomic, weak) UIButton *weakButton;
These properties are not set via Interface Builder (i.e. they will always remain nil as long as I don't set them explicitly in code).
这些属性不是通过接口构建器来设置的(也就是说,只要我不在代码中显式地设置它们,它们将始终保持为nil)。
I also added a category on UIButton to know exactly when it is dealloced:
我还在UIButton上添加了一个类别来确切地知道它何时被释放:
@implementation UIButton (test)
- (void)dealloc { NSLog(@"Dealloc called."); }
@end
I have the following code in the viewDidLoad
of the UIViewController:
我在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.");
When I run that code, it fails on the second assertion (B). The log shows:
当我运行该代码时,它在第二个断言(B)上失败。
- Setting to nil
- 设置为零
- Done setting to nil
- 完成设置为零
- * Assertion failure in -[ViewController viewDidLoad]
- *在-[ViewController viewDidLoad]中断言失败
- * Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'B: Weak button should be nil.'
- *因未捕获异常“NSInternalInconsistencyException”而终止app,原因:“B:弱按钮应为nil”。
However, when I comment out the first assertion:
然而,当我注释掉第一个断言时:
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.");
The code runs fine with this in the log:
该代码在日志中运行良好:
- Setting to nil
- 设置为零
- Dealloc called.
- Dealloc调用。
- Done setting to nil
- 完成设置为零
Notice how the dealloc is not being called at the proper time in the first scenario.
请注意,在第一个场景中,dealloc是如何在适当的时间被调用的。
Why is that first NSAssert causing this weird behavior? Is this a bug or am I doing something wrong?
为什么第一个NSAssert会导致这种奇怪的行为?这是bug还是我做错了什么?
(I am on iOS 6.1)
(我上的是iOS 6.1)
1 个解决方案
#1
7
Reading a weak variable may cause the pointed-to object to be retained and autoreleased. The object will then remain alive at least as long as the current autorelease pool.
读一个弱变量可能会导致指向对象被保留,并且自动生成。然后,对象将保持活动状态,至少与当前的自动上传池一样长。
In your case, your first NSAssert()
reads the weak variable. The button object is retained and autoreleased. Setting self.strongButton=nil
does not cause the button to be deallocated, because it is still alive in the autorelease pool, so the weak variable does not become nil.
在您的示例中,第一个NSAssert()读取弱变量。保留并自动加载按钮对象。设置自我。strongButton=nil不会导致按钮被释放,因为它仍然存在于autorelease池中,所以弱变量不会变成nil。
When you comment out the NSAssert()
, the weak variable is no longer read, so the button is not retained and autoreleased, so it does in fact die when you set self.strongButton=nil
.
当您注释掉NSAssert()时,弱变量将不再被读取,因此不会保留按钮并自动加载,因此当您设置self.strongButton=nil时,它实际上就会死亡。
#1
7
Reading a weak variable may cause the pointed-to object to be retained and autoreleased. The object will then remain alive at least as long as the current autorelease pool.
读一个弱变量可能会导致指向对象被保留,并且自动生成。然后,对象将保持活动状态,至少与当前的自动上传池一样长。
In your case, your first NSAssert()
reads the weak variable. The button object is retained and autoreleased. Setting self.strongButton=nil
does not cause the button to be deallocated, because it is still alive in the autorelease pool, so the weak variable does not become nil.
在您的示例中,第一个NSAssert()读取弱变量。保留并自动加载按钮对象。设置自我。strongButton=nil不会导致按钮被释放,因为它仍然存在于autorelease池中,所以弱变量不会变成nil。
When you comment out the NSAssert()
, the weak variable is no longer read, so the button is not retained and autoreleased, so it does in fact die when you set self.strongButton=nil
.
当您注释掉NSAssert()时,弱变量将不再被读取,因此不会保留按钮并自动加载,因此当您设置self.strongButton=nil时,它实际上就会死亡。