块中的强引用,会保留吗?

时间:2016-06-16 03:59:57

标签: objective-c objective-c-blocks

我从公司的文档中发现了这段代码:

__weak __typeof(self)weakSelf = self;
dispatch_async(dispatch_get_main_queue(),
^{
      __strong __typeof(weakSelf)strongSelf = weakSelf; 
      // Do stuff
});

它会被保留吗?

3 个答案:

答案 0 :(得分:5)

在一个区块中捕获weak引用有两个原因。

  1. 避免保留周期

  2. 创建无操作情况。

  3. 前者已被讨论过令人作呕。第二个更有趣。

    示例

      

    有问题的块是图像下载的完成处理程序。下载完成后,将以图像视图显示。

    如果图像视图已被解除分配(例如用户已切换到新视图),则无需执行任何操作。没有保留周期的危险,因为图像视图没有对块的引用。但是,捕获weak引用允许在块执行之前取消分配图像视图。因此,如果用户在下载图像之前切换视图,则该块最终无效,因为其weak引用已被nil编辑。如果图像视图在块的执行过程中被解除分配也没关系,因为它只是将图像视图上的操作转换为无操作,而不是将整个块转换为无操作。

    但是,有时块会想要无操作行为,但只有当引用开始时(或在代码路径中达到某个点)时引用已经是nil。如果在块执行时对象是活动的,则块必须完整地执行。它无法中途停止,因为该对象在其他某个线程上被释放。

    示例

      

    完成块的目的是将由字符串定义的标题添加到图像中。如果已经取消分配字符串,则不添加标题。但是,如果字符串在后处理开始时仍处于活动状态,则必须保持活动状态以避免尝试使用nil引用创建属性字符串,因为这会导致崩溃。

    在这种情况下,使用weak引用捕获字符串是正确的,因此可以通过其他某个线程释放它(导致没有标题)。但是,在块中使用字符串之前,必须先捕获它strong以避免在创建属性字符串时发生崩溃。

答案 1 :(得分:0)

块外的弱副本就足够了。

__weak __typeof(self)weakSelf = self;
dispatch_async(dispatch_get_main_queue(),
^{
      // silliness: __strong __typeof(weakSelf)strongSelf = weakSelf; 
      // Do stuff with weakSelf here
});

事实上,这也没关系:

dispatch_async(dispatch_get_main_queue(),
^{
    // self self self, go ahead and mention self here
});

一个人不能做的就是在某个地方复制那个块,然后在块中的某个地方提一下。

@property (nonatomic, strong) void (^myBlock)(void);

self.myBlock = ^void(void) {
    // don't mention self here!
};

这个想法是块保留了他们提到的对象,我们试图避免循环,所以object -> block -> another_object很好,但是object -> block -> another_object -> any amount of indirection -> object是一个循环,这很糟糕。

循环很糟糕,因为如果某个对象保留在其他位置,则无法取消分配,因此无法取消分配它保留的内容。如果两件东西相互保留,那么它们都会被卡住,无法解除分配,因为每件东西都被某些东西保留下来。

编辑直到今天我误解的是弱变量的强大副本并不总是愚蠢的。它可能是相关的,但有意义的情况是高度合格的。)

答案 2 :(得分:0)

如果您使用此:

__weak __typeof(self)weakSelf = self;
dispatch_async(dispatch_get_main_queue(),
^{ 
    // Do stuff
});

在执行块时,可能会释放自我。因此我们最好将weakSelf转换为strongSelf,以确保self保留在内存中,直到块完成执行。

使用__strong __typeof(weakSelf)strongSelf = weakSelf后,self将引用本地堆栈变量。所以它不会被保留。