block本質(zhì)
- 將 “函數(shù)” 及 “執(zhí)行其上下文” 封裝起來(lái)的 “對(duì)象”
- block的調(diào)用就是函數(shù)的調(diào)用
eg:
int main(int argc, const char * argv[]) {
int (^add)(int a,int b) = ^(int a,int b){
return a + b;
};
NSLog(@"%d",add(10,20));
return 0;
}
使用 “clang -rewrite-objc main.m”查看編譯之后的部分內(nèi)容
__block_impl 結(jié)構(gòu)體中發(fā)現(xiàn)有 isa 指針林艘,所以說(shuō)block是Objective-C對(duì)象
block捕獲變量特性
在block中使用外部變量時(shí),block會(huì)捕獲其變量架诞,具體規(guī)則如下
- 局部變量為基本數(shù)據(jù)類(lèi)型:捕獲其值
- 局部變量為對(duì)象類(lèi)型:連同所有權(quán)修飾符一起捕獲
- 局部變量為靜態(tài)的:以指針的形式捕獲
- 全局變量:不捕獲
- 全局靜態(tài)變量:不捕獲
int testGlobalVar = 0;
static int testGlobalStaticVar = 0;
int main(int argc, const char * argv[]) {
int testVar = 0;
__strong id obj = [[NSObject alloc]init];
static int testStaticVar = 0;
void(^test)(void) = ^(){
NSLog(@"局部變量為基本數(shù)據(jù)類(lèi)型%d",testVar);
NSLog(@"局部變量為對(duì)象類(lèi)型%@",obj);
NSLog(@"局部變量為靜態(tài)的%d",testStaticVar);
NSLog(@"全局變量%d",testGlobalVar);
NSLog(@"全局靜態(tài)變量%d",testGlobalStaticVar);
};
test();
return 0;
}
將上述代碼編譯后际长,我們?cè)倏確_main_block_impl_0結(jié)構(gòu)體中這幾個(gè)變量在其中的類(lèi)型酿秸,就可以更好理解block的捕獲特性
由于捕獲的特性蒸绩,當(dāng)我們?cè)赽lock中使用對(duì)象類(lèi)型時(shí)车柠,需要注意循環(huán)引用
__block
使用場(chǎng)景:在blcok內(nèi)部對(duì)捕獲的值進(jìn)行賦值
- 局部變量為基本數(shù)據(jù)類(lèi)型相种、對(duì)象類(lèi)型,需要__block
- 靜態(tài)局部變量积仗、全局變量疆拘、全局靜態(tài)變量,不需要__block寂曹,因?yàn)殪o態(tài)局部變量不捕獲其指針哎迄,全局變量、全局靜態(tài)變量不捕獲
原理:
如圖隆圆,編譯后的文件漱挚,我們發(fā)現(xiàn),局部數(shù)據(jù)類(lèi)型變量a渺氧、局部對(duì)象類(lèi)型obj竟然變成了結(jié)構(gòu)體實(shí)例
__Block_byref_a_0結(jié)構(gòu)體實(shí)例的成員變量__forwarding持有指向該實(shí)例自身的指針
block內(nèi)存管理
類(lèi) | 對(duì)應(yīng)對(duì)象的存儲(chǔ)域 |
---|---|
_NSConcreteStackBlock | 棧 |
_NSConcreteGlobalBlock | 數(shù)據(jù)區(qū)域(.data區(qū)) |
_NSConcreteMallocBlock | 堆 |
update by 2019年04月05日22:22:12
我用幾個(gè)例子來(lái)描述各個(gè)情景下的內(nèi)存管理
栗子1:block不捕獲任何外部變量旨涝,分配在全局區(qū)
栗子2:block捕獲局部變量,分配在堆區(qū)
栗子3:block捕獲局部靜態(tài)變量侣背,分配在全局區(qū)
栗子4:block捕獲全局變量白华,分配在全局區(qū)
栗子5:block捕獲全局靜態(tài)變量,分配在全局區(qū)
5個(gè)栗子贩耐,blcok不是分配在堆區(qū)弧腥,就是分配在全局區(qū),什么時(shí)候分配在棧區(qū)呢潮太?
截取官方文檔的一個(gè)圖管搪,可以發(fā)現(xiàn),當(dāng)發(fā)送copy消息的時(shí)候铡买,會(huì)將block分配在堆區(qū)更鲁,但是我們并沒(méi)有發(fā)任何copy消息呀,why寻狂?因?yàn)橄到y(tǒng)已經(jīng)偷偷給我們發(fā)送了copy消息
怎么不讓系統(tǒng)幫我們呢岁经?
栗子6:
我們看到編譯器給了我們警告
Assigning block literal to a weak variable; object will be released after assignment 將 block 分配給 weak 變量; 對(duì)象將在分配后釋放
用好類(lèi)型別名
為常用的 block 類(lèi)型創(chuàng)建 typedef
用 typedef 重新定義block類(lèi)型,可以使 block 變量用起來(lái)更加簡(jiǎn)單
typedef int(^Add)(int a,int b);
int main(int argc, const char * argv[]) {
Add add = ^(int a,int b){
return a + b;
};
NSLog(@"%d",add(10,20));
return 0;
}
如果給你帶來(lái)了一點(diǎn)點(diǎn)幫助蛇券,就點(diǎn)個(gè)贊吧??