-
Block類型是一個C級別的語法和運行機制。
block圖.png
實例:
//定義有返回值和參數的block
int (^sumBlock2)(int x, int y) = ^ int (int a, int b) {
return a + b;
};
//調用有返回值的block
NSLog(@"%d", sumBlock2(4, 8));
- typedef使用
//給無參無返回值block變量起別名;
//格式: void (^新類型名)();
typedef void (^newType)();
//用新的類型定義block變量 newType t1;
t1 = ^{
NSLog(@"我是使用newType定義出來的變量t1的值");
};
//調用block
t1();
有參數有返回值的block起別名
//給有參數有返回值的block起別名
typedef int(^blockType2)(int ,int );
blockType2 b2 = ^(int x,int y){
return x>y?x:y;
};
//max保存的是代碼塊執行的結果
int max = b2(119,45);
- 函數指針
//調用函數
int s = sum(10, 119); //函數名存放的是函數的首地址
//定義函數指針
int (*p)(int a,int b); //p 函數指針變量
typedef int (*p1)(int a,int b); //給返回值是int 并且有兩個參數的函數指針起一個別名 別名是p1 (是一個類型)
p = sum;
p1 = a
s = (*p)(10,119);
NSLog(@"s = %d",s);
訪問外部變量
- 注意在block代碼塊的內部使用外部變量的時候注意
1)在block定義的時候,把block外部的變量的值copy到了內存的堆區
2)拷貝的過程中使用了const(以const的形式把外部變量做了一個copy)--要想修改值使用__block - 注意:一旦把使用__block修飾某個變量,注意block之后,使用的都是 堆區的變量
-
__block
修飾符 告訴編譯器,i的值可以在block內部修改(忽略檢查)
block作為函數參數
//通過函數,傳遞一個參數,
void test(void (^myblock)()){
if (myblock) {
//調用block
myblock();
}
}
//兩種方式實現
//定義一個代碼塊,打印
void (^b1)()=^{
NSLog(@"**********");
NSLog(@"**********");
NSLog(@"哈哈哈");
};
//調用
test(b1);
test(^{
NSLog(@"wwwwwwww");
});
block作為方法的返回值
//聲明
typedef void(^blockType)();
-(blockType)test2;
//實現
-(blockType)test2{
return ^{
NSLog(@"test2 return block");
};
}
//調用
//返回值是block類型的方法
blockType b1 = [p test2];
b1();
三種類型的block
根據Block在內存中的位置分為三種類型NSGlobalBlock,NSStackBlock, NSMallocBlock。 NSGlobalBlock:類似函數,位于代碼段; NSStackBlock:位于棧內存,函數返回后Block將無效; NSMallocBlock:位于堆內存。
- 全局block (NSGlobalBlock),定義在函數外面的block是global的。
如果函數內部的 block,但是沒有捕獲任何自動變量,那么它也是全局的(ARC和MRC都一樣)。 - 棧block
- 堆block 則是對棧block copy 得來。對全局block copy 不會有任何作用,返回的依然是全局block。
block類型變量內存管理參數為什么要使用 copy
1.不管在MRC還是在ARC,使用assign 修飾的block,都是棧block,棧block會被提前釋放。
2.在ARC下 block類型的變量 strong 相當于 copy。但是我們不會直接寫成strong 而是寫成 copy
block的內存隱患
Block_copy(bb); //copy block到堆區(bb位于堆區了)
Block_release(bb); //釋放b1的空間(b1已經是一個堆block)