【问题标题】:When and why would I want to declare a local variable as __weak using ARC?何时以及为什么要使用 ARC 将局部变量声明为 __weak?
【发布时间】:2012-01-10 15:54:06
【问题描述】:

Mike Ash has written this introduction to ARC 他介绍了如下内容:

__weak Foo *_weakFoo = [object foo];

我为什么要对本地临时变量执行此操作? __weak 是一个归零引用,一旦引用的对象被释放,它将自动将 _weakFoo 指针设置为 nil。此外,__weak 仅在 iOS >= 5 中可用。

当我这样做时,我什么时候会遇到麻烦?:

Foo *_weakFoo = [object foo];

这总是期望返回一个对象或零。我的猜测是这样的:

Foo *_weakFoo = [object foo];
[self doSomethingStupid]; // does something bad so foo gets deallocated
[_weakFoo doIt]; // CRASH! msg sent to deallocated instance 0x123456

ARC 仍然困扰我的一件事是:它什么时候知道我不再需要一个对象?我会争辩说,当我将指针设置为 nil 或其他内容时,它会发现此所有者不再需要先前引用的对象,因此可能会消失。但关键是:我将它设置为 nil。所以无论如何它都是零!

那么 __weak 对于局部变量什么时候有意义,我必须在其他地方做什么疯狂的事情才能真正需要它?

【问题讨论】:

    标签: ios iphone xcode automatic-ref-counting weak-references


    【解决方案1】:

    如果我必须在块内操作self 以避免保留循环,我会使用__weak 局部变量。考虑这个示例,我使用 GCD 和块来执行对字符串的网络请求,然后将其设置在类声明的标签上,在本例中为 TurtlesViewController

    __weak TurtlesViewController *weakSelf = self;
    dispatch_queue_t networkQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    
    dispatch_async(networkQueue, ^{
    
        // Kick off a network task for some data that is going to populate a label declared on our class
        NSString *returnString = [networkDataSource retrieveTurtleTime];
    
        // Dispatch back to the main thread to populate the UILabel
        dispatch_async(dispatch_get_main_queue(), ^{
    
            // Using self.label here creates a retain cycle. Self owns the block and the block has captured self
            self.label.text = returnString;
    
            // Instead, we use weakSelf for our reference to the label as it will be torn down by ARC at the end of the loop.
            weakSelf.label.text = returnString;
        });
    });
    

    【讨论】:

    • 怎么会有保留周期呢?
    • @openfrog - 这个特定的块可能不会成为保留周期的最大风险,但我遇到的一个是基于块的通知观察者(使用 NSNotificationCenter 的-addObserverForName:object:queue: usingBlock:) .如果您在对象中设置这样的观察者,并在 self 上引用某些内容,您将设置一个循环,因为对象保持在块上,块保持在对象上。
    • 写完这篇文章后,我意识到这不是最好的例子,因为 dispatch_async() 复制块,但只复制到方法结束。一个更好的例子是使用 NSBlockOperation,因为这样的实例在对象的生命周期内拥有传入的块,从而更有可能保持循环。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-08-01
    • 2019-06-12
    • 2011-08-16
    • 2012-08-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多