什么是 Weak-Strong Dance ?
在使用的 Block
時晾嘶, 除了使用 __weak
修飾符去避免循環(huán)引用外妓雾,還可以通過名為 Weak-Strong Dance
的方式去避免循環(huán)引用。 其實 Weak-Strong Dance
并不是一個新東西垒迂,它只是 __weak
的一個升級版本械姻。主要目的是為了避免在極端情況下 __weak
這種情況會出現(xiàn)的問題。
使用 __weak 形式避免循環(huán)引用有什么問題?
typedef void(^blk_t)();
@interface TObject : NSObject
@property (nonatomic) blk_t block;
@end
@implementation TObject
- (instancetype)init {
self = [super init];
__weak typeof(self) weakSelf = self;
self.block = ^() {
NSLog(@"block start...");
NSLog(@"self is %@", weakSelf);
NSLog(@"block end...");
};
return self;
}
@end
上面這段代碼在大部分的情況下都是可行的,Block 捕獲 weakSelf楷拳。當(dāng) self 被釋放的時候绣夺, weakSelf 也會被設(shè)為 nil
。self 持有的 Block 當(dāng)然也會被設(shè)為 nil
欢揖。但是在多線程的情況當(dāng) block 執(zhí)行到 NSLog(@"block start...")
時陶耍, 在另一個線程中此時 self 被釋放。 weakSelf 也被設(shè)為 nil
她混。那么這個例子中就會打印出 self is nil
烈钞。這沒出現(xiàn)啥問題。 但是如果是移除 KVO 的觀察者坤按,或者添加到 NSDictionary 中這樣的 API毯欣。值為 nil
就會造成程序 carsh。
通過 Weak-Strong Dance 安全的避免循環(huán)引用
- (instancetype)init {
self = [super init];
__weak typeof(self) weakSelf = self;
self.block = ^() {
__strong typeof(weakSelf) strongSelf = weakSelf;
NSLog(@"%@", strongSelf);
};
return self;
}
通過對上面的代碼增加了一句 __strong typeof(weakSelf) strongSelf = weakSelf;
來避免了上面說的極端情況臭脓,這就是 Weak-Strong Dance
酗钞。 這句話的作用在于一執(zhí)行 Block 的時候,就利用一個強(qiáng)引用去持有 weakSelf来累。 這樣在 Block 執(zhí)行的過程中就不用擔(dān)心 self 會被釋放了砚作, 因為此時有個強(qiáng)引用持有他。這也不會造成循環(huán)引用嘹锁,因為 Block 執(zhí)行時 strongSelf
才會指向 self葫录,Block 執(zhí)行完成后 strongSelf
就隨著超出作用域而被系統(tǒng)回收了。
拓展&加深
在 @kuailejim 的文章 Weak-Strong-Dance真的安全嗎兼耀?》 看到個新的觀點: 當(dāng)剛進(jìn)入 Block 時還沒有為 strongSelf 賦值時压昼,此時 weakSelf 被設(shè)置成 nil
,那 strongSelf 的值還是 nil
瘤运。 還是不夠安全窍霞,所以在對 strongSelf 賦值后,再做一次非空判斷拯坟。這樣就絕對沒毛病了:
__weak typeof(self) weakSelf = self;
self.block = ^() {
__strong typeof(weakSelf) strongSelf = weakSelf;
if (strongSelf == nil) {return;};
NSLog(@"%@", strongSelf);
};