什么是Block
-
Block是將函數(shù)及其執(zhí)行上下文封裝起來的對(duì)象异剥。
#import "MCBlock.h" @implementation MCBlock - (void)method { static int multiplier = 6; int(^Block)(int) = ^int(int num) { return num * multiplier; }; Block(2); } @end
經(jīng)過命令行重寫
clang -rewrite-objc MCBlock.m
,生成文件MCBlock.cpp//I代表實(shí)例方法 static void _I_MCBlock_method(MCBlock * self, SEL _cmd) { int multiplier = 6; int(*Block)(int) = ((int (*)(int))&__MCBlock__method_block_impl_0((void *)__MCBlock__method_block_func_0, &__MCBlock__method_block_desc_0_DATA, multiplier)); ((int (*)(__block_impl *, int))((__block_impl *)Block)->FuncPtr)((__block_impl *)Block, 2); }
struct __MCBlock__method_block_impl_0 { struct __block_impl impl; struct __MCBlock__method_block_desc_0* Desc; int multiplier; __MCBlock__method_block_impl_0(void *fp, struct __MCBlock__method_block_desc_0 *desc, int _multiplier, int flags=0) : multiplier(_multiplier) { impl.isa = &_NSConcreteStackBlock; impl.Flags = flags; impl.FuncPtr = fp; Desc = desc; } }; static int __MCBlock__method_block_func_0(struct __MCBlock__method_block_impl_0 *__cself, int num) { int multiplier = __cself->multiplier; // bound by copy return num * multiplier; }
struct __block_impl { void *isa;//isa指針,Block是對(duì)象的標(biāo)志 int Flags; int Reserved; void *FuncPtr;//函數(shù)指針 };
Block的調(diào)用即是函數(shù)的調(diào)用
Block截獲變量
//滴滴面試
{
static int multiplier = 6;
int(^Block)(int) = ^int(int num)
{
return num * multiplier;
};
multiplier = 4;
NSLog(@"result is %d",Block(2));//result is 12
}
- 局部變量
- 基本數(shù)據(jù)類型
- 對(duì)象類型
- 靜態(tài)局部變量
- 全局變量
- 靜態(tài)全局變量
關(guān)于Block的截獲特性你是否有了解慎璧,以及Block的截獲特性又是怎樣的?
變量的截獲方式
- 對(duì)于基本數(shù)據(jù)類型的局部變量截獲其值挺身。
- 對(duì)于對(duì)象類型的局部變量連同所有權(quán)修飾符一起截獲摔笤。
- 以指針形式截獲局部靜態(tài)變量。
- 不截獲全局變量个粱、靜態(tài)全局變量。
#import "MCBlock.h"
@implementation MCBlock
//全局變量
int global_var = 4;
//靜態(tài)全局變量
static int static_global_var = 5;
- (void)method
{
//基本數(shù)據(jù)類型的局部變量
int var = 1;
//對(duì)象類型的局部變量
__unsafe_unretained id unsafe_obj = nil;
__strong id strong_obj = nil;
static int static_var = 3;
void(^Block)(void) = ^{
NSLog(@"局部變量<基本數(shù)據(jù)類型> var %d", var);
NSLog(@"局部變量<__unsafe_unretained 對(duì)象類型> var %@", unsafe_obj);
NSLog(@"局部變量<__strong 對(duì)象類型> var %@", strong_obj);
NSLog(@"靜態(tài)變量 %d", static_var);
NSLog(@"全局變量 %d", global_var);
NSLog(@"靜態(tài)全局變量 %d", static_global_var);
};
Block();
}
@end
clang -rewrite-objc -fobjc-arc MCBlock.m
// @implementation MCBlock
int global_var = 4;
static int static_global_var = 5;
struct __MCBlock__method_block_impl_0 {
struct __block_impl impl;
struct __MCBlock__method_block_desc_0* Desc;
//截獲局部變量的值
int var;
//連同所有權(quán)修飾符一起截獲
__unsafe_unretained id unsafe_obj;
__strong id strong_obj;
//以指針形式截獲局部變量
int *static_var;
//對(duì)全局變量翻翩、靜態(tài)全局變量不截獲
__MCBlock__method_block_impl_0(void *fp, struct __MCBlock__method_block_desc_0 *desc, int _var, __unsafe_unretained id _unsafe_obj, __strong id _strong_obj, int *_static_var, int flags=0) : var(_var), unsafe_obj(_unsafe_obj), strong_obj(_strong_obj), static_var(_static_var) {
impl.isa = &_NSConcreteStackBlock;
impl.Flags = flags;
impl.FuncPtr = fp;
Desc = desc;
}
};
static void __MCBlock__method_block_func_0(struct __MCBlock__method_block_impl_0 *__cself) {
int var = __cself->var; // bound by copy
__unsafe_unretained id unsafe_obj = __cself->unsafe_obj; // bound by copy
__strong id strong_obj = __cself->strong_obj; // bound by copy
int *static_var = __cself->static_var; // bound by copy
NSLog((NSString *)&__NSConstantStringImpl__var_folders_hk_552cymzd23v5b0db528k_jbr0000gn_T_MCBlock_a2d5da_mi_0, var);
NSLog((NSString *)&__NSConstantStringImpl__var_folders_hk_552cymzd23v5b0db528k_jbr0000gn_T_MCBlock_a2d5da_mi_1, unsafe_obj);
NSLog((NSString *)&__NSConstantStringImpl__var_folders_hk_552cymzd23v5b0db528k_jbr0000gn_T_MCBlock_a2d5da_mi_2, strong_obj);
NSLog((NSString *)&__NSConstantStringImpl__var_folders_hk_552cymzd23v5b0db528k_jbr0000gn_T_MCBlock_a2d5da_mi_3, (*static_var));
NSLog((NSString *)&__NSConstantStringImpl__var_folders_hk_552cymzd23v5b0db528k_jbr0000gn_T_MCBlock_a2d5da_mi_4, global_var);
NSLog((NSString *)&__NSConstantStringImpl__var_folders_hk_552cymzd23v5b0db528k_jbr0000gn_T_MCBlock_a2d5da_mi_5, static_global_var);
}
static void __MCBlock__method_block_copy_0(struct __MCBlock__method_block_impl_0*dst, struct __MCBlock__method_block_impl_0*src) {_Block_object_assign((void*)&dst->unsafe_obj, (void*)src->unsafe_obj, 3/*BLOCK_FIELD_IS_OBJECT*/);_Block_object_assign((void*)&dst->strong_obj, (void*)src->strong_obj, 3/*BLOCK_FIELD_IS_OBJECT*/);}
static void __MCBlock__method_block_dispose_0(struct __MCBlock__method_block_impl_0*src) {_Block_object_dispose((void*)src->unsafe_obj, 3/*BLOCK_FIELD_IS_OBJECT*/);_Block_object_dispose((void*)src->strong_obj, 3/*BLOCK_FIELD_IS_OBJECT*/);}
static struct __MCBlock__method_block_desc_0 {
size_t reserved;
size_t Block_size;
void (*copy)(struct __MCBlock__method_block_impl_0*, struct __MCBlock__method_block_impl_0*);
void (*dispose)(struct __MCBlock__method_block_impl_0*);
} __MCBlock__method_block_desc_0_DATA = { 0, sizeof(struct __MCBlock__method_block_impl_0), __MCBlock__method_block_copy_0, __MCBlock__method_block_dispose_0};
static void _I_MCBlock_method(MCBlock * self, SEL _cmd) {
int var = 1;
__attribute__((objc_ownership(none))) id unsafe_obj = __null;
__attribute__((objc_ownership(strong))) id strong_obj = __null;
static int static_var = 3;
void(*Block)(void) = ((void (*)())&__MCBlock__method_block_impl_0((void *)__MCBlock__method_block_func_0, &__MCBlock__method_block_desc_0_DATA, var, unsafe_obj, strong_obj, &static_var, 570425344));
((void (*)(__block_impl *))((__block_impl *)Block)->FuncPtr)((__block_impl *)Block);
}
// @end
__block修飾符
-
一般情況下都许,對(duì)被截獲變量進(jìn)行賦值操作需添加
__block
修飾符 - 對(duì)靜態(tài)局部變量稻薇,全局變量,靜態(tài)全局變量進(jìn)行賦值時(shí)候胶征,不需要
__block
修飾符
{
NSMutableArray *array = [NSMutableArray array];
void(^Block)(void) = ^{
[array addObject:@123];
};
Block();
}
上面的array
是否需要__block
修飾塞椎?
上面只是對(duì)array進(jìn)行了使用,而不是賦值操作睛低,只有賦值操作才需要
__block
修飾的變量變成了對(duì)象
{
__block int multiplier = 6;
int(^Block)(int) = ^int(int num)
{
return num * multiplier;
};
multiplier = 4;
Block(2); //8
}
所以上面的代碼multiplier = 4;
實(shí)際上變成了(multiplier._forwarding->multiplier) = 4;
Block的類型
- _NSConcreteGlobalBlock
- _NSConcreteStackBlock
- _NSConcreteMallocBlock
Block的Copy操作
假如聲明一個(gè)對(duì)象的成員變量是Block案狠,而在棧上去創(chuàng)建Block,同時(shí)賦值給成員變量的Block钱雷,如果成員變量的Block沒有使用copy關(guān)鍵字的話骂铁,當(dāng)我們具體通過成員變量去訪問對(duì)應(yīng)的Block,可能就由于棧上的Block被釋放而引起崩潰罩抗。
棧上Block的銷毀
棧上Block的copy
在MRC環(huán)境拉庵,假如對(duì)棧上Block進(jìn)行copy操作,Block會(huì)引起內(nèi)存泄漏套蒂,因?yàn)锽lock copy之后钞支,堆上Block沒有額外的成員變量去指向它,就像對(duì)一個(gè)對(duì)象進(jìn)行alloc操作之后操刀,沒有調(diào)用對(duì)應(yīng)的release的效果是一樣的,產(chǎn)生內(nèi)存泄漏烁挟。
棧上Block進(jìn)行copy之后,
__forwarding
指針是指向堆上的__block
變量骨坑,堆上的Block__forwarding
指針指向自身信夫。
__forwarding
總結(jié)
//百度面試題
{
__block int multiplier = 10;
_blk = ^int(int num) {
return num * multiplier;
};
multiplier = 6;
[self executeBlock];
}
- (void)executeBlock
{
int result = _blk(4);
NSLog(@"result is %d", result); //result is 24
}
__forwarding
存在的意義
不論在任何內(nèi)存位置,都可以順利的訪問同一個(gè)__block
變量卡啰。
Block的引用循環(huán)
__block
的引用循環(huán)
{
__block MCBlock *blockSelf = self;
_blk = ^int(int num) {
//var = 2
return num * blockSelf.var;
};
_blk(3);
}
- 在MRC下,不會(huì)產(chǎn)生引用循環(huán)警没。
- 在ARC下匈辱,會(huì)產(chǎn)生循環(huán)引用,引起內(nèi)存泄漏杀迹。?
{
__block MCBlock *blockSelf = self;
_blk = ^int(int num) {
//var = 2
int result = num * blockSelf.var;
blockSelf = nil;
return result;
};
_blk(3);//如果Block長時(shí)間等不到調(diào)用亡脸,則引用循環(huán)會(huì)存在。
}