众所周知,在块内使用强自我会导致保留周期和内存泄漏。通常的做法是在块中使用弱自我,还是在块中将弱自身分配给强对象然后再使用它更好,这样在块执行期间不会释放弱自我?这是否重要,因为无论如何弱自我将被排除在外?
答案 0 :(得分:4)
由于弱变量的易变性,您应该小心使用它们。如果您在多线程环境中使用弱变量,那么将弱变量分配给强变量并在使用前检查nil被认为是一种好习惯。这将确保不会在方法中间释放对象,从而导致意外结果。
考虑以下情况:
__weak id var;
//...
if(var != nil)
{
//var was released here on another thread and there are not more retaining references.
[anotherObj performActionWithAnObjThatMustNotBeNil:var]; //<- You may crash here.
}
可以将编译器配置为在连续访问弱变量时发出警告。
另一方面,如果你的用法在主线程中,并且对象的所有调用都在主线程上,那么这个问题没有实际意义,因为对象将在块调用之前或之后被释放,因此它可以安全地直接访问弱变量。
答案 1 :(得分:4)
这里有两个可能容易混淆的问题:
__weak
引用是否有可能在方法中间成为nil
?
id __strong strongObject = ...;
id __weak weakObject = strongObject;
dispatch_async(dispatch_get_main_queue(), ^{
[weakObject method1]; // if weakObject is non-nil here
[weakObject method2]; // can it become non-nil here?
});
是的! Xcode will even warn you about it.
如果在self
左值上调用该方法,nil
是否可以在方法中间成为__weak
?
id __strong strongObject = ...;
id __weak weakObject = strongObject;
dispatch_async(dispatch_get_main_queue(), ^{
// is it possible for weakObject to be deallocated
// while methodUsingSelf is being called?
[weakObject methodUsingSelf];
});
- (void)methodUsingSelf {
NSLog(@"%@", self); // Could this be non-nil
NSLog(@"%@", self); // while this is nil?
}
没有! Joe Groff,来自Apple的Swift团队,said so:
ObjC ARC保证自我保持活力,而自我的方法则是 执行。
Clang's official ARC documentation在Semantics /阅读小节中介绍了这种情况:
在对a执行左值到右值的转换时发生读取 对象左值。
对于
__weak
个对象,保留当前的指针,然后释放 在当前的完整表达结束时。这必须执行 原子地关于作业和最终的释放 指针对象。
因此,在__weak
变量上调用方法大致相当于以下手动保留/释放(MRR)代码:
id retainedObject = ...;
id assignedObject = strongObject;
dispatch_async(dispatch_get_main_queue(), ^{
{
[assignedObject retain];
[assignedObject methodUsingSelf];
[assignedObject release];
}
});
当然,在MRR中,[assignedObject retain];
可能会崩溃,因为对象assignedObject
指向可能已被解除分配,因此assignedObject
可能指向垃圾。 ARC doesn't have this problem because it zeroes weak
references
答案 2 :(得分:1)
我认为即使使用weak
也能正常工作并在需要时保留,在使用之前将其分配给强者会使其更具可读性,并且可以免费使用&#34; ...:
__weak id weakThing = thing;
thing.someBlock = ^{
if (weakThing) {
id strongThing = weakThing;
strongThing doThisWithThat...
}
};
编译器不会抱怨并且它是安全的,也许并不那么重要 - 对John Doe很容易理解,他将在明天尝试阅读此代码....
答案 3 :(得分:0)
你可以继续使用弱者。只有当您尝试直接访问自我&gt; ivar而不是通过财产时,您才需要使用强大的自我。