不使用__block修飾:
int num = 1; self.myBlock = ^(){ NSLog(@"block num == %d",num); }; num = 2; self.myBlock(); NSLog(@"last num == %d",num); // 輸入結果: // 2016-09-13 13:13:15.362 block2[7543:562614] block num == 1 // 2016-09-13 13:13:15.363 block2[7543:562614] last num == 2
num 使用__block修飾後:
__block int num = 1; self.myBlock = ^(){ NSLog(@"block num == %d",num); }; num = 2; self.myBlock(); NSLog(@"last num == %d",num); // 輸出結果: // 2016-09-13 13:14:20.964 block2[7574:570584] block num == 2 // 2016-09-13 13:14:20.964 block2[7574:570584] last num == 2
若是不用__block修飾變量,在block內強行修改變量會報錯:多線程
增長__block後,能夠在block內部修改num:spa
__block int num = 1; self.myBlock = ^(){ num = 3; NSLog(@"block num == %d",num); }; num = 2; self.myBlock(); NSLog(@"last num == %d",num); // 輸出結果: // 2016-09-13 13:16:44.961 block2[7632:585368] block num == 3 // 2016-09-13 13:16:44.962 block2[7632:585368] last num == 3
block調用完後再修改num:線程
__block int num = 1; self.myBlock = ^(){ num = 3; NSLog(@"block num == %d",num); }; self.myBlock(); num = 2; NSLog(@"last num == %d",num); // 輸出結果: // 2016-09-13 13:18:38.332 block2[7681:599563] block num == 3 // 2016-09-13 13:18:38.333 block2[7681:599563] last num == 2
block對對象類型的使用和對基本數據類型的使用同樣:指針
不用__block修飾:code
NSString *str = @"1"; self.myBlock = ^(){ NSLog(@"block str == %@",str); }; str = @"2"; self.myBlock(); NSLog(@"last str == %@",str); // 輸出結果: // 2016-09-13 13:23:03.091 block2[7815:628689] block str == 1 // 2016-09-13 13:23:03.092 block2[7815:628689] last str == 2
使用__block修飾:對象
__block NSString *str = @"1"; self.myBlock = ^(){ NSLog(@"block str == %@",str); }; str = @"2"; self.myBlock(); NSLog(@"last str == %@",str); // 輸出結果: // 2016-09-13 13:25:17.199 block2[7867:638529] block str == 2 // 2016-09-13 13:25:17.199 block2[7867:638529] last str == 2
block內部修改對象:blog
__block NSString *str = @"1"; self.myBlock = ^(){ str = @"3"; NSLog(@"block str == %@",str); }; str = @"2"; self.myBlock(); NSLog(@"last str == %@",str); // 輸出結果: // 2016-09-13 13:27:49.440 block2[7937:651966] block str == 3 // 2016-09-13 13:27:49.441 block2[7937:651966] last str == 3
block調用完後再修改對象:內存
__block NSString *str = @"1"; self.myBlock = ^(){ str = @"3"; NSLog(@"block str == %@",str); }; self.myBlock(); str = @"2"; NSLog(@"last str == %@",str); // 輸出結果: // 2016-09-13 13:29:03.705 block2[7973:660957] block str == 3 // 2016-09-13 13:29:03.705 block2[7973:660957] last str == 2
總結:同步
__block的使用:ast
block對基本數據類型和對象類型的使用注意是同樣的。即:
不管是基本數據類型仍是對象類型,若是想在block內部改變外面變量的值,必須用__block修飾;若是外面的值改變也要影響block內部值,也必須用__block修飾。(與block外面的變量的值保持同步)
即若是想內部改變影響外部或者外部改變影響內部,那麼變量必須用__block修飾
若是不加__block修飾,那麼block會捕獲變量的值,在以後不受外面變量的改變而改變;而且也不能在block內部修改變量的值
若是想在block內部修改變量的值,必須用__block修飾
block循環引用:
伴隨着block可以捕獲變量的能力的一個問題就是, 循環引用, 在ARC中, 只要不是用到純C語言的庫,管理內存的工做都不須要咱們完成, 可是循環引用倒是咱們須要解決的, 最多見的就是當block捕獲的變量是一個對象的屬性(方法)的時候, 也就是會捕獲到self, 那麼這個時候就可能會形成循環引用(block屬性應該被標記爲copy), 解決方法也很簡單, 使用一個對self弱引用的指針便可, 這個寫法就不少了, 筆者習慣的寫法是: __weak typeof(self) weakSelf = self;
, 那麼在block中使用weakSelf
替代self
調用相關的屬性或者方法, 就不會形成循環引用
weakSelf和strongSelf:
使用weakSelf可以解決block捕獲self形成的循環引用的內存泄漏問題, 可是帶來的另外一個問題就是, 特別是在多線程中,可能在block中代碼正在執行
的時候, self被銷燬了, 由於使用weakSelf捕獲到的是self的弱引用, 那麼後續的代碼就不可以繼續執行了, 這個時候爲了保證在這個block中self即便被銷燬block裏面的代碼也能正常執行, 咱們須要的另外一個操做就是, 將weakSelf強引用一次, 讓他的引用計數加1, 就能處理這個問題, 就是Apple在wwdc中提到的weak-strong-dance
, 筆者習慣的書寫方式是: __strong typeof(self) strongSelf = weakSelf;
,,, 固然這個必需要明白的是, 這個block裏面的strongSelf可以保證裏面代碼執行完畢的前提是程序可以執行到block, 若是在執行block以前self已經被銷燬了, 那麼這個block確定是不會被調用的(block的引用計數已經爲0).