什么是Block?
Block 又稱為“塊” 或 “代碼塊”蜀细,作用是用來保存代碼恋昼,保存在其內(nèi)部的代碼塊 如果Block不被調(diào)用 這段代碼就不會(huì)執(zhí)行
在OC中Block的基本格式是這樣的
返回值類型 (^block名) (參數(shù)類型 和 數(shù)量) = ^(形參 和 數(shù)量){
//code
}队寇;
Block的本質(zhì)上也是一個(gè)OC對(duì)象 它內(nèi)部也有個(gè)isa指針
Block是封裝了函數(shù)調(diào)用以及函數(shù)調(diào)用環(huán)境(比如參數(shù)和返回值)的OC對(duì)象
Block是封裝了函數(shù)及其上下文的OC對(duì)象
1、寫一個(gè)簡單的block:
@autoreleasepool {
appDelegateClassName = NSStringFromClass([AppDelegate class]);
MyBlock myBlock = ^{
};
NSLog(@"myBlock:%@",myBlock);//myBlock:<__NSGlobalBlock__: 0x10bfde038>
myBlock();
}
轉(zhuǎn)成底層代碼
typedef void(*MyBlock)(void);
//Block的本質(zhì)
struct __block_impl {
void *isa;//isa指針(Block的類型-->指向Class)
int Flags;
int Reserved;
void *FuncPtr;//封裝代碼塊的地址
};
struct __test_block_impl_0 {
struct __block_impl impl;
struct __test_block_desc_0* Desc;
// 構(gòu)造函數(shù)(類似于OC的init方法),返回結(jié)構(gòu)體對(duì)象
__test_block_impl_0(void *fp, struct __test_block_desc_0 *desc, int flags=0) {
impl.isa = &_NSConcreteStackBlock;
impl.Flags = flags;
impl.FuncPtr = fp;
Desc = desc;
}
};
static void __test_block_func_0(struct __test_block_impl_0 *__cself) {
}
static struct __test_block_desc_0 {
size_t reserved;
size_t Block_size;
} __test_block_desc_0_DATA = { 0, sizeof(struct __test_block_impl_0)};
void test(){
MyBlock myBlock = ((void (*)())&__test_block_impl_0((void *)__test_block_func_0, &__test_block_desc_0_DATA));
((void (*)(__block_impl *))((__block_impl *)myBlock)->FuncPtr)((__block_impl *)myBlock);
}
2晴弃、block內(nèi)部捕獲變量
int a_q = 10;//全局變量
static int b_q = 10;//全局靜態(tài)變量
typedef void(^MyBlock)(void);
void test(){
int a = 10;//局部變量
static int b = 10;//局部靜態(tài)變量
MyBlock myBlock = ^{
NSLog(@"a=%d", a);//a=10
NSLog(@"b=%d", b);//b=20
NSLog(@"a_q=%d", a_q);//a_q=20
NSLog(@"b_q=%d", b_q);//b_q=20
};
a = 20;
b = 20;
a_q = 20;
b_q = 20;
myBlock();
}
轉(zhuǎn)成底層代碼
typedef void(*MyBlock)(void);
//Block的本質(zhì)
struct __block_impl {
void *isa;//isa指針(Block的類型-->指向Class)
int Flags;
int Reserved;
void *FuncPtr;//封裝代碼塊的地址
};
int a_q = 10;
static int b_q = 10;
typedef void(*MyBlock)(void);
struct __test_block_impl_0 {
struct __block_impl impl;
struct __test_block_desc_0* Desc;
int a;
int *b;
__test_block_impl_0(void *fp, struct __test_block_desc_0 *desc, int _a, int *_b, int flags=0) : a(_a), b(_b) {
impl.isa = &_NSConcreteStackBlock;
impl.Flags = flags;
impl.FuncPtr = fp;
Desc = desc;
}
};
static void __test_block_func_0(struct __test_block_impl_0 *__cself) {
int a = __cself->a; // bound by copy
int *b = __cself->b; // bound by copy
NSLog((NSString *)&__NSConstantStringImpl__var_folders_r0_rjxg_z6540vblvmqqv4klgsm0000gn_T_main_df2751_mi_0, a);
NSLog((NSString *)&__NSConstantStringImpl__var_folders_r0_rjxg_z6540vblvmqqv4klgsm0000gn_T_main_df2751_mi_1, (*b));
NSLog((NSString *)&__NSConstantStringImpl__var_folders_r0_rjxg_z6540vblvmqqv4klgsm0000gn_T_main_df2751_mi_2, a_q);
NSLog((NSString *)&__NSConstantStringImpl__var_folders_r0_rjxg_z6540vblvmqqv4klgsm0000gn_T_main_df2751_mi_3, b_q);
}
static struct __test_block_desc_0 {
size_t reserved;
size_t Block_size;
} __test_block_desc_0_DATA = { 0, sizeof(struct __test_block_impl_0)};
void test(){
int a = 10;
static int b = 10;
MyBlock myBlock = ((void (*)())&__test_block_impl_0((void *)__test_block_func_0, &__test_block_desc_0_DATA, a, &b));
a = 20;
b = 20;
a_q = 20;
b_q = 20;
((void (*)(__block_impl *))((__block_impl *)myBlock)->FuncPtr)((__block_impl *)myBlock);
}
分析:
1纯路、局部變量a:可以看到我們Block內(nèi)部有一個(gè)(int _a)變量,局部變量a直接傳值給_a;(在局部變量中 auto局部變量出了作用域就會(huì)銷毀 為了避免執(zhí)行block時(shí) 變量不存在 所以auto變量在Block內(nèi)部被直接賦值為當(dāng)前值)
2或油、局部靜態(tài)變量b:可以看到我們Block內(nèi)部有一個(gè)(int _b)變量,局部靜態(tài)變量b把b(指針)傳給*_b;(static變量一直存在于內(nèi)存中不必有此擔(dān)憂,所以存儲(chǔ)的是變量指針驰唬,可以隨時(shí)取出最新值顶岸。)
3、全局變量a_q和全局靜態(tài)變量b_q:Block內(nèi)部沒有生成對(duì)應(yīng)的變量(如果是全局變量 Block使用時(shí)不用捕獲 直接訪問 所以得到的也全部都是最新值叫编。)
總結(jié):局部變量之所以需要捕獲 因?yàn)槲覀兪强绾瘮?shù)使用的 聲明和使用不是在一個(gè)作用域內(nèi)
注意:self這個(gè)變量也是局部變量 也會(huì)被block捕獲,因?yàn)樵贠C中所有的方法編譯后都是自帶兩個(gè)參數(shù) 一個(gè)是實(shí)例對(duì)象 一個(gè)是SEL _cmd
所以Block中如果用到self辖佣,self也會(huì)被捕獲。且Block內(nèi)部的self屬性 指向我們傳進(jìn)去的self
所以 我們也能理解為什么會(huì)造成循環(huán)引用了吧搓逾。
self捕獲
int a_q = 10;
static int b_q = 10;
typedef void(^MyBlock)(void);
- (void)test{
int a = 10;
static int b = 10;
MyBlock myBlock = ^{
NSLog(@"a=%d", a);//a=10
NSLog(@"b=%d", b);//b=20
NSLog(@"a_q=%d", a_q);//a_q=20
NSLog(@"b_q=%d", b_q);//b_q=20
NSLog(@"%@",self);
};
a = 20;
b = 20;
a_q = 20;
b_q = 20;
myBlock();
}
轉(zhuǎn)成底層代碼
int a_q = 10;
static int b_q = 10;
typedef void(*MyBlock)(void);
struct __ViewController__test_block_impl_0 {
struct __block_impl impl;
struct __ViewController__test_block_desc_0* Desc;
int a;
int *b;
ViewController *self;
__ViewController__test_block_impl_0(void *fp, struct __ViewController__test_block_desc_0 *desc, int _a, int *_b, ViewController *_self, int flags=0) : a(_a), b(_b), self(_self) {
impl.isa = &_NSConcreteStackBlock;
impl.Flags = flags;
impl.FuncPtr = fp;
Desc = desc;
}
};
static void __ViewController__test_block_func_0(struct __ViewController__test_block_impl_0 *__cself) {
int a = __cself->a; // bound by copy
int *b = __cself->b; // bound by copy
ViewController *self = __cself->self; // bound by copy
NSLog((NSString *)&__NSConstantStringImpl__var_folders_r0_rjxg_z6540vblvmqqv4klgsm0000gn_T_ViewController_16af55_mi_0, a);
NSLog((NSString *)&__NSConstantStringImpl__var_folders_r0_rjxg_z6540vblvmqqv4klgsm0000gn_T_ViewController_16af55_mi_1, (*b));
NSLog((NSString *)&__NSConstantStringImpl__var_folders_r0_rjxg_z6540vblvmqqv4klgsm0000gn_T_ViewController_16af55_mi_2, a_q);
NSLog((NSString *)&__NSConstantStringImpl__var_folders_r0_rjxg_z6540vblvmqqv4klgsm0000gn_T_ViewController_16af55_mi_3, b_q);
NSLog((NSString *)&__NSConstantStringImpl__var_folders_r0_rjxg_z6540vblvmqqv4klgsm0000gn_T_ViewController_16af55_mi_4,self);
}
static void __ViewController__test_block_copy_0(struct __ViewController__test_block_impl_0*dst, struct __ViewController__test_block_impl_0*src) {_Block_object_assign((void*)&dst->self, (void*)src->self, 3/*BLOCK_FIELD_IS_OBJECT*/);}
static void __ViewController__test_block_dispose_0(struct __ViewController__test_block_impl_0*src) {_Block_object_dispose((void*)src->self, 3/*BLOCK_FIELD_IS_OBJECT*/);}
static struct __ViewController__test_block_desc_0 {
size_t reserved;
size_t Block_size;
void (*copy)(struct __ViewController__test_block_impl_0*, struct __ViewController__test_block_impl_0*);
void (*dispose)(struct __ViewController__test_block_impl_0*);
} __ViewController__test_block_desc_0_DATA = { 0, sizeof(struct __ViewController__test_block_impl_0), __ViewController__test_block_copy_0, __ViewController__test_block_dispose_0};
static void _I_ViewController_test(ViewController * self, SEL _cmd) {
int a = 10;
static int b = 10;
MyBlock myBlock = ((void (*)())&__ViewController__test_block_impl_0((void *)__ViewController__test_block_func_0, &__ViewController__test_block_desc_0_DATA, a, &b, self, 570425344));
a = 20;
b = 20;
a_q = 20;
b_q = 20;
((void (*)(__block_impl *))((__block_impl *)myBlock)->FuncPtr)((__block_impl *)myBlock);
}