我从公司的文档中发现了这段代码:
__weak __typeof(self)weakSelf = self;
dispatch_async(dispatch_get_main_queue(),
^{
__strong __typeof(weakSelf)strongSelf = weakSelf;
// Do stuff
});
它会被保留吗?
答案 0 :(得分:5)
在一个区块中捕获weak
引用有两个原因。
避免保留周期
创建无操作情况。
前者已被讨论过令人作呕。第二个更有趣。
示例强>
有问题的块是图像下载的完成处理程序。下载完成后,将以图像视图显示。
如果图像视图已被解除分配(例如用户已切换到新视图),则无需执行任何操作。没有保留周期的危险,因为图像视图没有对块的引用。但是,捕获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将引用本地堆栈变量。所以它不会被保留。