Objective-C:我们应该在使用它之前使用弱自我还是将弱自我分配给强者?

时间:2014-04-25 15:21:03

标签: objective-c objective-c-blocks

众所周知,在块内使用强自我会导致保留周期和内存泄漏。通常的做法是在块中使用弱自我,还是在块中将弱自身分配给强对象然后再使用它更好,这样在块执行期间不会释放弱自我?这是否重要,因为无论如何弱自我将被排除在外?

4 个答案:

答案 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 documentationSemantics /阅读小节中介绍了这种情况:

  

在对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而不是通过财产时,您才需要使用强大的自我。