首先,什麼是block:block其實就是一個代碼塊,把你想要執行的代碼封裝在這個代碼塊里,等到需要的時候再去調用。那block是OC對象嗎?答案是肯定的 做一道很簡單的關於block的測試題。: 這道題是我公司面試題中的一道,來面試的都是至少兩年工作經驗的,但是很鬱悶,這道題絕大多數人寫的都是6。 ...
首先,什麼是block:block其實就是一個代碼塊,把你想要執行的代碼封裝在這個代碼塊里,等到需要的時候再去調用。那block是OC對象嗎?答案是肯定的
做一道很簡單的關於block的測試題。:
1 // 2 int (^testBlock) (int) = ^(int num) { 3 return num++; 4 }; 5 NSLog(@"%d", testBlock(testBlock(testBlock(3))));
這道題是我公司面試題中的一道,來面試的都是至少兩年工作經驗的,但是很鬱悶,這道題絕大多數人寫的都是6。。正確結果為:3。
以下講解的內容均是ARC環境下。
一、block的分類- NSStackBlock:棧block
- NSMallocBlock:堆block
- NSGlobalBlock:全局block
//棧block int i = 0; NSLog(@"%@",^{NSLog(@"%d",i);});//輸出結果 __NSStackBlock__: 0x7fff57aada78>註意:不是沒有強指針(copy或strong)引用的block,就是棧block,也有可能是全局block(下麵會介紹什麼是全局block)。 2.NSMallocBlock: 特點:沒有強指針引用即銷毀,生命周期由程式員手動管理
棧block如果有強指針引用或copy修飾的成員屬性引用就會被拷貝到堆中,變成堆block
//堆block int j = 0; void(^mallocBlock)() = ^ { NSLog(@"%d",j); }; NSLog(@"%@",mallocBlock);//輸出結果 <__NSMallocBlock__: 0x7f8cd351db80>上面代碼也沒用看到strong 或 copy修飾符,但是為什麼會強引用的,因為在ARC環境下,我們在聲明變數的時候,前面是會被預設加上 __strong 修飾符的。所以我們在ARC下聲明的Block一般都是堆block。 3.NSGlobalBlock: 特點:命長,有多長?很長很長,人在塔在(應用程式在它就在) 沒有用到外界變數,或者只用到全局變數、靜態(static)變數的block就是全局block 對於全局block,用weak,strong,還是copy修飾都是可以的。(但最好不用用weak)
//全局block void (^globalBlock) () = ^ { NSLog(@"%d",staticNum); }; NSLog(@"%@",globalBlock); //輸出結果 <__NSGlobalBlock__: 0x108152110>
註意:如果block中沒有用到外界變數,不管他是用什麼修飾符修飾,他都是全局block!
例如:
void (^global2Block) () = ^ { NSLog(@"globalBlock"); }; NSLog(@"%@",global2Block); // 輸出結果 <__NSGlobalBlock__: 0x1023a0150>
二、block對外界變數的捕獲
1.1 基本數據類型:局部變數
block會拷貝該變數的值當做常量使用,外界修改變數的值不會影響block內部,且block內部不能對其修改
block內部修改外界變數i的值直接報錯,如果想要修改,可以在int a = 0前面加上關鍵字__block,此時i等效於全局變數或靜態變數
int a = 0; void (^block1)() = ^ { // a++ 直接修改a會報錯 NSLog(@"a = %d",a); }; a++; block1(); //輸出結果 a = 0; __block int b = 0; void (^block2) () = ^ { NSLog(@"b = %d",b); // 輸出結果 b = 0; b = 2; }; block2(); NSLog(@"b = %d",b); //輸出結果 b = 2;
1.2 基本數據類型:成員變數(實例變數),靜態變數,全局變數
block直接訪問變數地址,在block內部可以修改變數的值,並且外部變數被修改後,block內部也會跟著變
self.num = 1; self.num ++; void (^block3) () = ^ { self.num++; }; block3(); NSLog(@"%d",self.num);//輸出結果為 3
2.1 指針類型: 局部變數
block會複製一份指針並強引用指針所指對象,且內部不能修改指針的指向,但是可以修改指針所指向對象的值
NSMutableString *str = @"abc".mutableCopy; void (^block4) () = ^ { // str = @"def"; 報錯 [str appendString:@"def"]; NSLog(@"str = %@",str); }; str = @"123".mutableCopy; block4(); //輸出結果為 "adbdef"
2.2 指針類型: 成員變數(實例變數),靜態變數,全局變數
block不會複製指針,但是會強引用該對象,內部可修改指針指向,block會強引用成員屬性\變數所屬的對象,這也是為什麼block內部用到self.xxx或_xxx可能會引起迴圈引用的原因
static NSString *staticStr = @"abc"; void (^block5) () = ^ { NSLog(@"staticStr = %@",staticStr); staticStr = @"def"; NSLog(@"staticStr = %@",staticStr); }; staticStr = @"123"; block5(); //輸出結果為 staticStr = 123 staticStr = def