研究工具:clang
創(chuàng)建一個(gè)名為block.c的源文件
#include <stdio.h>
int main(){
^{printf("Hello ,World!\n");}();
return 0;
}
命令行輸入:clang ?-rewrite-objc block.c ? 可在block.c所在的目錄下看到一個(gè)block.cpp文件進(jìn)行分析
block的主要構(gòu)成
isa指針:所有對(duì)象都有該指針,用于實(shí)現(xiàn)對(duì)象的相關(guān)功能
invoke:函數(shù)指針,指向具體的block實(shí)現(xiàn)的函數(shù)指針
descriptor:標(biāo)示該block的附加信息,主要是size大小,以及copy和dispose函數(shù)的指針
variables:block能夠訪問它外部的局部變量,就是因?yàn)檫@些變量(或者變量的地址)復(fù)制到了結(jié)構(gòu)體中
結(jié)構(gòu)體本身并不附帶任何額外信息
創(chuàng)建block時(shí),實(shí)際就是在方法中聲明一個(gè)struct,并且初始化該struct的成員。而執(zhí)行block時(shí),就是調(diào)用那個(gè)單獨(dú)的C函數(shù),并把該struct指針傳遞過去。
在objc中,根據(jù)對(duì)象的定義,凡是首地址是*isa的結(jié)構(gòu)體指針,都可以認(rèn)為是對(duì)象(id).
常見的3種類型的block
_NSConcreteGlobalBlock,全局靜態(tài)block,不會(huì)訪問任何外部變量
_NSConcreteStackBlock,保存在棧中的block,block返回時(shí)被銷毀
_NSConcreteMallocBlock,保存在堆中的block,引用計(jì)數(shù)為0時(shí)被銷毀
只有一個(gè)block被調(diào)用copy方法的時(shí)候,系統(tǒng)才會(huì)將這個(gè)block復(fù)制到堆上,從而產(chǎn)生NSConcreteMallocBlock類型的block
局部變量在block內(nèi)不能被修改
static void__main_block_func_0(struct__main_block_impl_0 *__cself) {
inti = __cself->i;// bound by copy
printf("%d",i);}
在block中引用的局部變量i,實(shí)際上是在聲明block時(shí),被復(fù)制到__main_block_impl_0結(jié)構(gòu)體的那個(gè)變量,block內(nèi)部修改變量i,不會(huì)影響到外部的變量i.
__block修改局部變量
struct__Block_byref_i_0 {
void*__isa;? //凡是首地址是*isa的結(jié)構(gòu)體指針,都可以認(rèn)為是對(duì)象(id).
__Block_byref_i_0 *__forwarding;
int __flags;
int __size;
int i;}
變量i,成了一個(gè)結(jié)構(gòu)體 在__main_block_impl_0 中引用著__Block_byref_i_0 *i;// by ref 結(jié)構(gòu)體指針 ,這樣就起到修改外部局部變量的作用
負(fù)責(zé)結(jié)構(gòu)體__Block_byref_i_0的內(nèi)存管理,增加了copy和dispose函數(shù)指針,用于在調(diào)用前后修改相應(yīng)變量的引用計(jì)數(shù)
static struct__main_block_desc_0 {
size_t reserved;
size_t Block_size;
void(*copy)(struct__main_block_impl_0*,struct__main_block_impl_0*);
void(*dispose)(struct__main_block_impl_0*);
} __main_block_desc_0_DATA = {0,sizeof(struct__main_block_impl_0), __main_block_copy_0, __main_block_dispose_0};
ARC對(duì)block類型的影響
int main(int argc,char* argv[]) {
@autoreleasepool{
int i =1024;
void(^block)(void) = ^{
printf("%d",i);
};
block();
NSLog(@"%@",block);
return0;}
}
非ARC運(yùn)行結(jié)果//10242016-06-14 10:46:03.238 MemoryInMRC[7473:3171916] <__NSStackBlock__: 0x7fff5a58f548>
ARC運(yùn)行結(jié)果//10242016-06-14 10:49:03.121 MemoryInMRC[7528:3174176] <__NSMallocBlock__: 0x7fe36a7003e0>
循環(huán)引用
self對(duì)block引用,block捕捉到self時(shí)
XYZBlockKeeper*__weakweakSelf=self; ?self.block=^{ ??[weakSelf doSomething];//捕獲到的是弱引用 ?}
如果捕獲到的是當(dāng)前對(duì)象的成員變量對(duì)象,同樣也會(huì)造成對(duì)self的引用
id ?tmpIvar=_ivar;//臨時(shí)變量,避免了self引用 ??self.block=^{ ??[tmpIvar msg]; ?}
block對(duì)變量的捕獲規(guī)則
靜態(tài)儲(chǔ)存區(qū)變量:全局變量、static修飾變量可以修改
block接受的參數(shù),可以修改
__block引用,可以修改。//bound by reference 如果時(shí)id類型則不會(huì)被block retain,必須手動(dòng)處理其內(nèi)存管理。
局部變量不可以修改//bound by copy