Block你應(yīng)該知道的事

Block 是將函數(shù)及其執(zhí)行上下文封裝起來(lái)的對(duì)象(結(jié)構(gòu)體)。Block的調(diào)用實(shí)質(zhì)上就是函數(shù)的調(diào)用。
----它的內(nèi)存是分配在棧上的,當(dāng)賦值的成員變量調(diào)用block時(shí),可能會(huì)因?yàn)闂I蠈?duì)應(yīng)的函數(shù)退出后在內(nèi)存中被釋放,而導(dǎo)致內(nèi)存崩潰。為了防止這個(gè)問(wèn)題,所以都是把block拷貝到堆中使用。
(在ARC下,使用copy和strong是一樣的,因?yàn)閎lock的retain是用copy來(lái)實(shí)現(xiàn)的,不過(guò)一般習(xí)慣性使用copy)

一、截獲變量
二、__block修飾符
三、避免block循環(huán)引用

一. block對(duì)不同變量的截獲
1>.對(duì)于基本數(shù)據(jù)類(lèi)型的局部變量只截獲其值。
2>.對(duì)于對(duì)象類(lèi)型的局部變量連同所有權(quán)修飾符一起截獲(強(qiáng)引用)。
3>.以指針形式截獲局部靜態(tài)變量。
4>.不截獲全局變量、靜態(tài)全局變量,直接進(jìn)行使用。

1.普通局部變量

int age = 10;
void(^localBlock)(void) = ^{
  NSLog(@"age = %d", age);
};
age = 18;
localBlock();            
//輸出age = 10;在age改變?yōu)?8之前,localBlock已經(jīng)截獲age的值(10)保存到localBlock結(jié)構(gòu)體中

二. __block修飾的變量
== 對(duì)于用 __block 修飾的變量(實(shí)際變成了一個(gè)結(jié)構(gòu)體),在截獲時(shí),block結(jié)構(gòu)體中保存了被修飾變量的地址和值,相當(dāng)于進(jìn)行指針拷貝。在block中可以修改這樣的變量的值。

__block int age = 10;
void(^localBlock)(void) = ^{
  NSLog(@"age = %d", ++age);
};
age = 18;
localBlock();
/*
輸出age = 19;另外解釋下當(dāng)去除__block修飾時(shí),會(huì)報(bào)錯(cuò)not assignable,
原因是局部變量保存在棧中,而block保存在堆中,不在一塊內(nèi)存空間里,而你block只知道我的值不知道我的家在哪里,當(dāng)然不能修改我。
*/

一般情況,對(duì)截獲的對(duì)象類(lèi)型局部變量進(jìn)行賦值操作需添加__block修飾符。賦值不等于使用(賦值是初始化,例如向已存在的數(shù)組中添加數(shù)據(jù)就不屬于賦值而只是使用,就不必使用__block修飾符)。

__block NSMutableArray *mArr = [[NSMutableArray alloc] init];
void(^localBlock)(void) = ^{
   //使用mArr 不需要 __block修飾
  [mArr addObject:@"1212"];   
   //給mArr賦值 需要 __block修飾
  mArr = [[NSMutableArray alloc] initWithObjects:@"222", nil];
};
localBlock();

三. 解決block的循環(huán)引用(讓你從此告別只會(huì)weakSelf的青蔥歲月)
1.weak->strong

self.name = @"James";
__weak typeof(self) weakSelf = self;
void(^localBlock)(void) = ^(){
  __strong typeof(self) strongself = weakSelf;
  //此處延遲兩秒執(zhí)行,模擬數(shù)據(jù)請(qǐng)求或者耗時(shí)操作
  dispatch_after(dispatch_time(DISPATCH_TIME_NOW,(int64_t)(2*NSEC_PER_SEC)),dispatch_get_main_queue(), ^{
      NSLog(@"%@",strongself.name);
  });
};
localBlock();

strongSelf使用解釋?zhuān)?/strong>
----試想一種情況,當(dāng)block在執(zhí)行耗時(shí)操作時(shí),當(dāng)前控制器被推出,而此時(shí)weakSelf由于在弱引用表中會(huì)馬上被釋放,block對(duì)self的弱引用沒(méi)有引用計(jì)數(shù)加持,就導(dǎo)致block作用域內(nèi)的self也會(huì)立刻置為nil。
----而如果在block的作用域中設(shè)置一個(gè)臨時(shí)變量對(duì)weakSelf進(jìn)行強(qiáng)引用,使block擁有對(duì)self的引用計(jì)數(shù),這樣即使在控制器被推出后,也因?yàn)閎lock強(qiáng)持有了控制器而不會(huì)馬上被釋放。
---而strongSelf由于是block作用域內(nèi)的局部變量,也會(huì)在block執(zhí)行完成后被自動(dòng)釋放池解決掉,此時(shí)控制器最終釋放,這樣既能避免循環(huán)引用也能夠保證block代碼塊的完整執(zhí)行。

2.__block修飾

self.name = @"James";
__block CurrentVC *vc = self;
void(^localBlock)(void) = ^(){
  //此處延遲兩秒執(zhí)行,模擬數(shù)據(jù)請(qǐng)求或者耗時(shí)操作
  dispatch_after(dispatch_time(DISPATCH_TIME_NOW,(int64_t)(2*NSEC_PER_SEC)),dispatch_get_main_queue(), ^{
      NSLog(@"%@",vc.name);
      //__block修飾的對(duì)象會(huì)被block強(qiáng)引用,需要手動(dòng)解環(huán)
      /*
        此處還要解釋的一點(diǎn)是,雖然上文說(shuō)__block修飾相當(dāng)于做了指針拷貝,
        但實(shí)際情況 vc是將原self的地址和內(nèi)容作為兩個(gè)引用保存在一個(gè)結(jié)構(gòu)體內(nèi),
        所以vc置nil并不影響外部的self
      */
      vc = nil;
  });
};
localBlock();
  1. self作為參數(shù)
void(^localBlock)(CurrentVC *vc) = ^(CurrentVC *vc){
      NSLog(@"%@",vc.name);
};
localBlock(self);

如果有疏漏的地方,也希望各位coder不吝指教

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Swift1> Swift和OC的區(qū)別1.1> Swift沒(méi)有地址/指針的概念1.2> 泛型1.3> 類(lèi)型嚴(yán)謹(jǐn) 對(duì)...
    cosWriter閱讀 11,634評(píng)論 1 32
  • Block在開(kāi)發(fā)中常用的,要想解決Block在開(kāi)發(fā)中遇到的問(wèn)題,我們需要了解Block的本質(zhì)、截獲變量的特性、__...
    字節(jié)碼閱讀 615評(píng)論 0 2
  • 在介紹Block之前通過(guò)一個(gè)簡(jiǎn)單的應(yīng)用場(chǎng)景認(rèn)識(shí)下Block 場(chǎng)景描述如下:TableView上面有多個(gè)Custom...
    黑_白_灰閱讀 1,476評(píng)論 4 29
  • 近來(lái)把《iOS與OS X多線程和內(nèi)存管理》這本書(shū)又掏出來(lái)看了一遍,這本書(shū)前前后后加起來(lái)看了能有三四遍了,每次看都有...
    老司機(jī)Wicky閱讀 2,421評(píng)論 5 46
  • 匆匆忙忙的回長(zhǎng)春考試,現(xiàn)在又要匆匆忙忙的走。晚上和朋友小聚了一下。逛吃逛吃,還是家里好啊
    愛(ài)咋咋地_134d閱讀 197評(píng)論 0 0

友情鏈接更多精彩內(nèi)容