標籤:
block內部引用外界對象的原則:block會對他內部所有的強指標進行強引用。驗證原理:
在主控制器中modal出ModalVC控制器,ModalVC中有強引用的block屬性,在block內部使用self,此時ModalVC便不會被釋放,不會執行dealloc方法。
驗證代碼:
循環參考的情況:
#import "ModalVC.h"@interface ModalVC ()// block屬性@property (nonatomic, strong) void(^block)();@end@implementation ModalVC- (void)viewDidLoad { [super viewDidLoad]; self.view.backgroundColor = [UIColor orangeColor]; // 定義block屬性 self.block = ^{ NSLog(@"%@", self); }; // 調用block self.block();}- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event { // 返會上一層控制器 [self dismissViewControllerAnimated:YES completion:nil];}- (void)dealloc { NSLog(@"ModalVC is release");}@end
改進方法: 將建立一個弱引用的self,供block內部使用
- (void)viewDidLoad { [super viewDidLoad]; self.view.backgroundColor = [UIColor orangeColor]; // 建立弱引用的self __weak typeof(self) weakSelf = self; // 定義block屬性 self.block = ^{ NSLog(@"%@", weakSelf); }; // 調用block self.block();}
block在多線程中問題block中使用的對象可能會被提前釋放。
#import "ModalVC.h"@interface ModalVC ()// block屬性@property (nonatomic, strong) void(^block)();@end@implementation ModalVC- (void)viewDidLoad { [super viewDidLoad]; self.view.backgroundColor = [UIColor orangeColor]; // 建立弱引用的self __weak typeof(self) weakSelf = self; // 定義block屬性 self.block = ^{ // 延時執行 dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ NSLog(@"%@", weakSelf); }); }; // 調用block self.block();}- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event { // 返會上一層控制器 [self dismissViewControllerAnimated:YES completion:nil];}- (void)dealloc { NSLog(@"ModalVC is release");}@end
在此種情況下,在ModalVC被modal出來後立即點擊螢幕,列印結如下,說明ModalVC在延時中的block執行時已經被提前釋放了,這種情況並不是我們想要的。
2016-01-16 10:06:19.206 004-block的循環參考問題[1863:54052] ModalVC is release2016-01-16 10:06:19.547 004-block的循環參考問題[1863:54052] (null)
記憶體分析
當ModalVC被VC控制器modal出來時,它被VC的presentedViewController屬性強引用,當點擊螢幕時,ModalVC控制器被dismiss掉了,presentedViewController強指標就無效了,ModalVC因為沒有強指標指向,就會被釋放掉,block也會被釋放掉,但是dispatch_after中的Block並沒有被釋放(被系統強引用著),兩秒後執行時列印出的weakSelf就為nil。
解決方案:
在block對象中再對weakSelf增加一個強指標
- (void)viewDidLoad { [super viewDidLoad]; self.view.backgroundColor = [UIColor orangeColor]; // 建立弱引用的self __weak typeof(self) weakSelf = self; // 定義block屬性 self.block = ^{ // 給weakSelf增加一個強指標 __strong typeof(self) strongSelf = weakSelf; // 延時兩秒 dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ NSLog(@"%@", strongSelf); }); }; // 調用block self.block();}
執行結果, 先列印ModalVC控制器,再釋放ModalVC控制器
2016-01-16 10:57:16.837 004-block的循環參考問題[2113:80213] <ModalVC: 0x7fdcd1d26850>2016-01-16 10:57:16.838 004-block的循環參考問題[2113:80213] ModalVC is release
記憶體分析
當點擊螢幕時,ModalVC控制器被dismiss掉了,presentedViewController強指標就無效了,但是ModalVC控制器仍然會被dispatch_after中block的strongSelf所強引用,所以不會被釋放掉。
block之---循環參考