块中的强引用,会被保留吗?
Strong reference in the block, it will be retained?
我从公司文档中发现了这段代码:
__weak __typeof(self)weakSelf = self;
dispatch_async(dispatch_get_main_queue(),
^{
__strong __typeof(weakSelf)strongSelf = weakSelf;
// Do stuff
});
会保留吗?
块外的弱拷贝就够了
__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
是一个循环,这很糟糕。
循环是不好的,因为如果一个对象保留在别处就不能被释放,所以它保留的东西也不能被释放。如果两个东西相互保留,那么它们都会被卡住,无法解除分配,因为每个东西都被某些东西保留了。
编辑 直到今天我还误解了弱变量的强副本并不总是愚蠢的。它可能是相关的,但有意义的情况是高度合格的)。
如果你使用这个:
__weak __typeof(self)weakSelf = self;
dispatch_async(dispatch_get_main_queue(),
^{
// Do stuff
});
在执行块时,Self 可能会被释放。所以我们最好将 weakSelf 转换为 strongSelf 以确保 self 保留在内存中,直到块执行完毕。
使用__strong __typeof(weakSelf)strongSelf = weakSelf
后,self 将引用本地堆栈变量。所以不会保留。
在一个块中捕获 weak
个引用有两个原因。
避免循环保留
创造 no-op 个情况。
前者已讨论ad-nauseum。第二个更有趣。
例子
The block in question is a completion handler for an image download. When the download is complete, it is to be displayed in an image view.
如果图像视图已经被解除分配(比如用户已切换到新视图),则不需要执行任何操作。没有保留循环的危险,因为图像视图没有引用块。但是,捕获 weak
引用允许在块执行之前释放图像视图。因此,如果用户在下载图像之前切换视图,该块最终什么都不做,因为它的 weak
引用已经被 nil
ed。图像视图是否在块的执行过程中被释放也无关紧要,因为它只是将图像视图上的操作变成 no-ops,而不是将整个块变成 no-op。
但是,有时块需要 no-op 行为,但前提是引用在开始时已经 nil
(或到达代码路径中的某个点)。如果在块执行时 object 处于活动状态,则块必须完整执行。它无法停止 half-way,因为 object 已在其他线程上释放。
例子
The purpose of the completion block is to add a caption, defined by a string, to the image. If the string has been deallocated already, no caption is to be added. However, if the string is still live when post-processing begins, it must remain live to avoid trying to create an attributed string with a nil
reference, because that leads to a crash.
在这种情况下,使用 weak
引用捕获字符串是合适的,这样它就可以被其他线程释放(导致没有标题)。但是,在块中使用该字符串之前,必须 strong
ly 捕获它以避免在创建属性字符串时发生崩溃。
我从公司文档中发现了这段代码:
__weak __typeof(self)weakSelf = self;
dispatch_async(dispatch_get_main_queue(),
^{
__strong __typeof(weakSelf)strongSelf = weakSelf;
// Do stuff
});
会保留吗?
块外的弱拷贝就够了
__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
是一个循环,这很糟糕。
循环是不好的,因为如果一个对象保留在别处就不能被释放,所以它保留的东西也不能被释放。如果两个东西相互保留,那么它们都会被卡住,无法解除分配,因为每个东西都被某些东西保留了。
编辑 直到今天我还误解了弱变量的强副本并不总是愚蠢的。它可能是相关的,但有意义的情况是高度合格的)。
如果你使用这个:
__weak __typeof(self)weakSelf = self;
dispatch_async(dispatch_get_main_queue(),
^{
// Do stuff
});
在执行块时,Self 可能会被释放。所以我们最好将 weakSelf 转换为 strongSelf 以确保 self 保留在内存中,直到块执行完毕。
使用__strong __typeof(weakSelf)strongSelf = weakSelf
后,self 将引用本地堆栈变量。所以不会保留。
在一个块中捕获 weak
个引用有两个原因。
避免循环保留
创造 no-op 个情况。
前者已讨论ad-nauseum。第二个更有趣。
例子
The block in question is a completion handler for an image download. When the download is complete, it is to be displayed in an image view.
如果图像视图已经被解除分配(比如用户已切换到新视图),则不需要执行任何操作。没有保留循环的危险,因为图像视图没有引用块。但是,捕获 weak
引用允许在块执行之前释放图像视图。因此,如果用户在下载图像之前切换视图,该块最终什么都不做,因为它的 weak
引用已经被 nil
ed。图像视图是否在块的执行过程中被释放也无关紧要,因为它只是将图像视图上的操作变成 no-ops,而不是将整个块变成 no-op。
但是,有时块需要 no-op 行为,但前提是引用在开始时已经 nil
(或到达代码路径中的某个点)。如果在块执行时 object 处于活动状态,则块必须完整执行。它无法停止 half-way,因为 object 已在其他线程上释放。
例子
The purpose of the completion block is to add a caption, defined by a string, to the image. If the string has been deallocated already, no caption is to be added. However, if the string is still live when post-processing begins, it must remain live to avoid trying to create an attributed string with a
nil
reference, because that leads to a crash.
在这种情况下,使用 weak
引用捕获字符串是合适的,这样它就可以被其他线程释放(导致没有标题)。但是,在块中使用该字符串之前,必须 strong
ly 捕获它以避免在创建属性字符串时发生崩溃。