我们知道,在块内使用strong self会导致保留循环和内存泄漏。常见做法是在块内使用weak self,或者将weak self分配给块内的strong self,然后在块内使用它,这样weak self在块执行期间不会被释放。由于weak self在任何情况下都会被清零,所以这是否重要呢?
我们知道,在块内使用strong self会导致保留循环和内存泄漏。常见做法是在块内使用weak self,或者将weak self分配给块内的strong self,然后在块内使用它,这样weak self在块执行期间不会被释放。由于weak self在任何情况下都会被清零,所以这是否重要呢?
由于弱变量的易变性,您应该谨慎使用它们。如果您在多线程环境中使用弱变量,最好的做法是将弱变量赋值给一个强变量,然后在使用之前检查是否为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.
}
编译器可以配置为在对弱变量进行连续访问时发出警告。
另一方面,如果您的使用在主线程中,并且所有对该对象的调用都在主线程上,则此问题是无关紧要的,因为对象将在块调用之前或之后释放,因此直接访问弱变量是安全的。
这里有两个容易混淆的可能问题:
__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甚至会警告您。
如果在下面示例中调用了一个方法并且该方法在__weak
lvalue上调用,那么self
是否可能在方法执行过程中变为nil
?
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?
}
不!苹果Swift团队的Joe Groff表示:
当self执行方法时,ObjC ARC会保证self一直存活。
Clang官方ARC文档在Semantics/Reading子节中涵盖了这种情况:
在对象lvalue上执行lvalue-to-rvalue转换时发生读取。
对于__weak对象,当前指针被保留,然后在当前完整表达式的末尾释放。这必须原子地与赋值和指针的最终释放同时执行。
因此,在__weak
变量上调用方法大致相当于以下手动保留/释放(MRR)代码:
id retainedObject = ...;
id assignedObject = strongObject;
dispatch_async(dispatch_get_main_queue(), ^{
{
[assignedObject retain];
[assignedObject methodUsingSelf];
[assignedObject release];
}
});
[assignedObject retain];
可能会崩溃,因为assignedObject
所指向的对象可能已被释放,所以assignedObject
可能指向垃圾。ARC没有这个问题,因为它将weak
引用置零。weak
会起作用并且在需要的时间内被保留,但在使用前将其分配给strong
将使其更易读和“无忧无虑”...:__weak id weakThing = thing;
thing.someBlock = ^{
if (weakThing) {
id strongThing = weakThing;
strongThing doThisWithThat...
}
};
你可以继续使用弱引用的self。唯一需要使用强引用的时候是当你尝试直接访问self->ivar而不是通过属性访问时。