本文為大地瓜原創(chuàng),歡迎知識共享,轉(zhuǎn)載請注明出處。
雖然你不注明出處我也沒什么精力和你計較。
作者微信號:christgreenlaw
本節(jié)是關于OC中極其重要的一個特性,BLOCK。
Overall
Block是iOS中一種比較特殊的數(shù)據(jù)類型。
一提到數(shù)據(jù)類型,應該就馬上能想到,它可以定義數(shù)據(jù)類型,作為形參,作為返回值(這三點應該是看到數(shù)據(jù)類型就馬上想到的)
應用場景:
- 動畫
- 多線程
- 集合遍歷
- 網(wǎng)絡請求回調(diào)
作用:
保存一段代碼,在恰當時間取出來使用(與函數(shù)很相似,但是比函數(shù)厲害)
指向函數(shù)的指針:
void method() {
printf(@"aaa");
}
void (*p)();
p = method;
p();
block變量,和函數(shù)一樣:
- 可以沒有返回值,沒有形參
- 也可以有返回值沒形參
- 可以有返回值有形參
- 可以沒返回值有形參
四種情況嘛
void (^methodBlock)();
- void代表block沒有返回值
- ()代表block保存的代碼沒有形參
- (^methodBlock)代表methodBlock是一個block變量,可以用于保存一段block代碼
methodBlock = ^{
printf(@"aaa");
};
寫法:
有參數(shù)的:
返回值類型 (^block變量名)(參數(shù)列表) = ^(參數(shù)列表){};//建議使用
返回值類型 (^block變量名)(參數(shù)列表) = ^返回值類型(參數(shù)列表){};
//開發(fā)中幾乎沒人把后面的返回值類型寫上
沒有參數(shù)的話:
返回值類型 (^block變量名)() = ^(){};
返回值類型 (^block變量名)() = ^{};//建議使用,括號多余
以上兩種寫法是一樣的
各種例子
int(^sum)(int a, int b) = {
return a + b;
;
sum(5,10);
-------------------
int (^sumBlock)(int,int);
sumBlock = ^(int v1, int v2){
return v1 + v2;
};
sumBlock(5,10);
-------------------------
void(^printFuck)(int) = ^(int num){
for(int i = 0; i < num; i++){
print("fuck");
}
};
printBlock(2);
block和typedef的結(jié)合
首先來看函數(shù)指針是怎么搞的:
int sum(int v1, v2) {
return v1 + v2;
}
int minus(int v1, v2) {
return v1 - v2;
}
typedef int (*calculate)(int, int);
int main(int argc, const char* argv[]) {
// int (*sumP)(int, int);
//sumP = sum;
calculate sumP = sum;
NSLog(@"sum = %i", sumP(1,2));
//int (*minusP)(int, int);
//minusP = minus;
calculate minusP = minus;
NSLog(@"minus = %i", minusP(1,2));
}
再來看看block是怎么搞的:
typedef int (^calculateBlock)(int, int);
int main(int argc, const char* argv[]) {
//int (^sumBlock)(int, int);
calculateBlock sumBlock = ^(int a, int b) {
return a + b;
};
NSLog(@"sum = %i", sumBlock(1,2));
//int (^minusBlock)(int, int);
calculateBlock minusBlock = ^(int a, int b) {
return a - b;
};
NSLog(@"minus = %i", minusBlock(1,2));
}
Block應用場景
傳遞數(shù)據(jù)兩個方式:代理(代碼分散)、block(代碼集中)
block用于傳遞一段代碼塊?。?!當你傳遞了一個block時,你可以在接收這個block的上下文中任何時候使用這段代碼!
Block注意事項
- block中可以訪問外面上下文的變量
- block中可以定義和外面同名的變量,若定義了,則會訪問本地定義的變量,而訪問不到外面了(作用域問題)
- 默認不可以在block中修改外界的變量值,因為block中的變量和外面的變量并不是同一個變量,若訪問了外面的變量 ,block會將外面的變量拷貝一份到堆內(nèi)存。(通過打印地址可以驗證)
- 也正因為這個拷貝問題,當你在外面修改了變量值,是不會修改block已經(jīng)拷貝的值的。也就是說,block只會捕獲其定義時上下文的變量值。
- 外界的變量之前加上
__block關鍵字,就可以在block內(nèi)部修改值了。且此時會影響外界的值??!
__block關鍵字做了什么?
為什么默認不能改?為什么加了就能改?
默認是值傳遞的。所以默認情況下修改不了外界。
加上__block后變?yōu)閭鬟f地址。
- block 默認情況下存儲在棧中,若對block對象進行copy(Block_copy方法),則轉(zhuǎn)移到堆中。若block在棧中,block訪問外界對象,不會對對象進行retain。若block在堆中,訪問外界對象就會進行retain。
- 若在block內(nèi)部訪問外界對象,一定要加上__block,只要加上了,就不會對其進行retain了。(消滅了因此而產(chǎn)生的內(nèi)存泄漏問題)。