簡述Block
block 是 C 語言的擴充功能,我們可以認為它是 帶有自動變量的匿名函數(shù)范删,同時也是一個對象蕾域。
- 首先Block聲明及定義語法,及其變形
1 標準定義
returnType(^blockName)(var_type) = ^returnType(var_type varName){ //操作 }
舉個?? :
void(^defalutBlock)(NSString *) = ^void(NSString *name){ NSlog(@"%@",name)}
2 省略縮寫
returnType(^blockName)(var_type) = ^(var_type varName){ //操作 }
舉個?? :
void(^defalutBlock)(NSString *) = ^(NSString *name){ NSlog(@"%@",name)}
3 typedef簡化Block的聲明
typedef return_type (^BlockTypeName)(var_type);
- 接下來我們看幾個面試題來分析下
1.
block
的原理是怎樣的瓶逃?本質(zhì)是什么?
2.__block
的作用是什么廓块?有什么使用注意點厢绝?
3.block
的屬性修飾詞為什么是copy
?使用block
有哪些使用注意带猴?
4.block
在修改NSMutableArray
昔汉,需不需要添加__block
?
問題1: block原理是什么拴清?本質(zhì)是什么靶病?
寫個block
int main(int argc, char * argv[]) {
int(^block)(int)=^int(int a)
{
return a;
};
block(8);
return 0;
}
通過使用clang命令,將.m文件轉(zhuǎn)換成.cpp文件clang -rewrite-objc main.m
int main(int argc, char * argv[]) {
int(*block)(int)=((int (*)(int))&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA));
((int (*)(__block_impl *, int))((__block_impl *)block)->FuncPtr)((__block_impl *)block, 8);
return 0;
}
C++定義block變量代碼 其中不難看出 將__main_block_impl_0
函數(shù)的地址賦值給了block
int(*block)(int)=((int (*)(int))&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA));
我們接著看下__main_block_impl_0
是什么口予?是一個結(jié)構(gòu)體
struct __main_block_impl_0 {
struct __block_impl impl;
struct __main_block_desc_0* Desc;
__main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, int flags=0) {
impl.isa = &_NSConcreteStackBlock;
impl.Flags = flags;
impl.FuncPtr = fp;
Desc = desc;
}
};
注意
:__main_block_impl_0
結(jié)構(gòu)體中 有同名的構(gòu)造函數(shù)__main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, int flags=0)
其中的fp 可以理解為方法的地址
我們可以看到__main_block_desc_0中存儲著兩個參數(shù)娄周,reserved和Block_size,并且reserved賦值為0而Block_size則存儲著__main_block_impl_0的占用空間大小沪停。最終將__main_block_desc_0結(jié)構(gòu)體的地址傳入__main_block_func_0中賦值給Desc
static struct __main_block_desc_0 {
size_t reserved;
size_t Block_size;
} __main_block_desc_0_DATA = { 0, sizeof(struct __main_block_impl_0)};
我們再來看下__block_impl
結(jié)構(gòu)體
struct __block_impl {
void *isa;
int Flags;
int Reserved;
void *FuncPtr;
};
我們可以發(fā)現(xiàn)__block_impl結(jié)構(gòu)體內(nèi)部就有一個isa指針煤辨。因此可以證明block本質(zhì)上就是一個oc對象裳涛。而在構(gòu)造函數(shù)中將函數(shù)中傳入的值分別存儲在__main_block_impl_0結(jié)構(gòu)體實例中,最終將結(jié)構(gòu)體的地址賦值給block众辨。
分析得出
- __block_impl結(jié)構(gòu)體中isa指針存儲著&_NSConcreteStackBlock地址端三,可以暫時理解為其類對象地址,block就是_NSConcreteStackBlock類型的
- block代碼塊中的代碼被封裝成__main_block_func_0函數(shù)鹃彻,F(xiàn)uncPtr則存儲著__main_block_func_0函數(shù)的地址郊闯。
- Desc指向__main_block_desc_0結(jié)構(gòu)體對象,其中存儲__main_block_impl_0結(jié)構(gòu)體所占用的內(nèi)存蛛株。
問題總結(jié):
此時已經(jīng)基本對block的底層結(jié)構(gòu)有了基本的認識团赁,上述代碼可以通過一張圖展示其中各個結(jié)構(gòu)體之間的關(guān)系。
本文有參考其他作者:
block文章---xxcc