概述
一般在使用Block時,為了防止循環(huán)引用,會使用__weak,因此下面主要驗證下是否在Block中必須使用__weak
驗證
- 新建一個類
Car
上面代碼主要是//Car.h #import <Foundation/Foundation.h> extern NSString *const CarNotificationName; typedef void(^SomeBlock)(void); @interface Car : NSObject @property (nonatomic, strong) SomeBlock myBlock; - (void)doWithBlock:(SomeBlock)block; - (void)carRunning; @end #import "Car.h" NSString *const CarNotificationName = @"carNotification"; @implementation Car - (Car *)init { self = [super init]; if (self) { [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(receiveNotification) name:CarNotificationName object:nil]; } return self; } - (void)receiveNotification { NSLog(@"Receiving Notification"); } - (void)carRunning { } - (void)doWithBlock:(SomeBlock)block { self.myBlock = block; self.myBlock(); } - (void)dealloc { [[NSNotificationCenter defaultCenter] removeObserver:self]; NSLog(@"dealloc"); } @end- 新建
Car類,只要Car類實例沒有被銷毀,就會處理CarNotificationName的通知 - 方法
- (void)doWithBlock:(SomeBlock)block;接收一個SomeBlock類型的參數(shù),并被賦值給一個strong類型的屬性。 - 方法
- (void)dealloc;注銷通知,并打印信息
- 新建
- 現(xiàn)在開始使用
Car類Car *car = [[Car alloc] init]; [[NSNotificationCenter defaultCenter] postNotificationName:CarNotificationName object:nil]; [car doWithBlock:^{ }]; car = nil; dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC * 5); dispatch_after(time, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ [[NSNotificationCenter defaultCenter] postNotificationName:CarNotificationName object:nil]; });- 首先獲取
Car類實例 - 緊接著發(fā)送
CarNotificationName通知,此時Car類實例會收到通知,并在控制臺輸出信息 - 然后調(diào)用
[car doWithBlock:^{}];方法,傳入的block中什么不做,然后將Car類實例設(shè)為nil,這時Car類實例被銷毀了 - 然后使用
dispatch_after在5秒后發(fā)送CarNotificationName通知,此時由于Car類實例被銷毀了,因此控制臺不會有信息打印出來
- 首先獲取
- 如果此時對上面代碼做如下改動
發(fā)現(xiàn)即使將[car doWithBlock:^{ [car carRunning]; }];Car類實例設(shè)為nil,5秒后Car類實例依然能夠接收CarNotificationName通知,并在控制臺打印了對應(yīng)的信息,也就是Car類實例并沒有被銷毀 - 原因就是循環(huán)引用產(chǎn)生
Car類中對SomeBlock是一個強(qiáng)引用
而在步驟3中的改動代碼中,在SomeBlock中反過來對@property (nonatomic, strong) SomeBlock myBlock;Car類實例也進(jìn)行了強(qiáng)引用,這就構(gòu)成了一個環(huán),導(dǎo)致它們兩個不能被銷毀。
解決方案
只要將上述的引用環(huán)斷開其中的一個就可以了,因此有兩種解決方法
- 在Block中使用
__weakCar * __weak weakCar = car; [car doWithBlock:^{ [weakCar carRunning]; }]; -
Car類中對SomeBlock弱引用@property (nonatomic, weak) SomeBlock myBlock;
結(jié)論
因此,可以確定不是在所有的Block中都要使用__weak,如果沒有構(gòu)成循環(huán)引用,或者對Block是弱引用就可以不必使用__weak
例如GCD或者[UIView animateWithDuration:5.0 animations:^{ }];中沒有構(gòu)成循環(huán)引用,就不必使用__weak,而在另一些情況如上述步驟3就需要使用__weak了。
備注
文中測試代碼已經(jīng)上到GitHub