相信有很多小伙伴跟我一樣糊啡,一直對 block 相交不深柱彻,雖然項目中可以使用豪娜,但還是了解的是不很透徹,今天就來解開這個心結哟楷。
文章介紹脈絡:
一瘤载,block 基礎知識
二,block 與 typedef
三卖擅,block與外部變量
四鸣奔,棧block與堆block
一,block 基礎知識
block包括兩部分:函數(shù)塊部分與變量部分
1惩阶,函數(shù)塊部分
函數(shù)塊用^符號表示挎狸,后面跟著一對花括號,括號里面是block的實現(xiàn)代碼
^{
NSLog(@"myBlock");
};
當有參數(shù)時
^(int value1, int value2){
return value1 + value2琳猫;
};
函數(shù)塊語法:^ 返回值類型 參數(shù)列表 表達式
其中伟叛,無返回值時,返回值類型可以用void表示脐嫂,也可以省略不寫统刮;無參數(shù)時,可以用“()”占位账千,也可以省略不寫
2侥蒙,變量部分
函數(shù)塊部分實際上就是一個值,可以是相關數(shù)據(jù)類型(int匀奏、float等)鞭衩。可以將函數(shù)塊的值賦值給變量娃善,賦值后可以像函數(shù)那樣使用變量
//變量聲明
int (^addBlock)(int,int);
//定義
addBlock = ^(int a, int b){
return a + b;
};
//調用
addBlock(5,7);
------
print: 12
addBlock 為block類型變量论衍,可以用來存儲函數(shù)塊
變量部分語法為: **返回值類型 (^變量名稱) (參數(shù)列表) **
二,block 與 typedef
利用 typedef 給 block 起別名聚磺,格式類似函數(shù)指針坯台,block變量的名稱就是別名
//格式:
typedef int (^AddBlock)(int,int);
j
AddBlock addblock = ^(int a, int b){
return a + b;
};
三,block 與外部變量
1瘫寝,block可以訪問外部變量
int additional = 5;
int (^ addBlock)(int, int) = ^(int a, int b){
return a + b + additional;
};
int sum = addBlock(5,7);
----------
print: 17
從例子可以看出蜒蕾,block 可以訪問外部(在該block聲明范圍內,函數(shù)塊外部)變量
2焕阿,block 默認不能修改外部變量
block訪問外部變量的實質是將變量copy一份到堆內存咪啡,所以實質上函數(shù)塊內部訪問的變量與外部變量不是同一個,因此暮屡,默認情況下撤摸,block 不可以修改外部變量的值
因此,在block塊執(zhí)行后褒纲,再修改外部變量對塊內變量沒有任何影響
int additional = 5;
int (^ addBlock)(int, int) = ^(int a, int b){
return a + b + additional;
};
additional = 8;
int sum = addBlock(5,7);
----------
print: 17
3愁溜,__block
修飾符
外部聲明變量時如果加__block
修飾符,那么函數(shù)塊訪問外部變量實際上是地址傳遞外厂,這樣就可以修改外部變量了
__block int additional = 5;
int (^ addBlock)(int, int) = ^(int a, int b){
additional = 10;
return a + b + additional;
};
int sum = addBlock(5,7);
四冕象,棧block與堆block
1,定義block的時候汁蝶,其所占的內存區(qū)域默認是分配在棧中的渐扮,也就是說block只在定義它的那個范圍內有效
void (^block)();
if( // 條件){
block = ^{
//代碼內容
};
}else{
block = ^{
//代碼內容
};
}
block();
上面代碼中block只在if、else語句中有效掖棉,離開這個范圍墓律,編譯器有可能把分配的內存覆蓋掉,因此block();
調用幔亥,有可能會導致崩潰耻讽。
2,對block進行copy操作帕棉,block 會被轉移到堆內存中
void (^block)();
if( // 條件){
block = ^{
//代碼內容
};
[block copy];
}else{
block = ^{
//代碼內容
};
[block copy];
}
block();
3针肥,在棧內存:Block訪問外部對象饼记,不對對象進行retain操作
Person *p = [[Person alloc] init];
NSLog(@"retainCount = %lu", [p retainCount]);
void (^myBlock)() = ^{
NSLog(@"block retainCount = %lu",[p retainCount]);
};
myBlock();
------------
print:
retainCount = 1
block retainCount = 1
4,在堆內存中:Block訪問外部對象慰枕,會對對象進行retain操作
Person *p = [[Person alloc] init];
NSLog(@"retainCount = %lu", [p retainCount]);
void (^myBlock)() = ^{
NSLog(@"block retainCount = %lu",[p retainCount]);
};
Block_copy(myBlock);
myBlock();
------------
print:
retainCount = 1
block retainCount = 2
以上是目前總結的基礎知識點具则,后續(xù)我會逐漸深入,并更新內容具帮,也歡迎伙伴們指正和補充博肋。
參考書籍:
《Effective Objective 2.0》
《Objective-C 高級編程》