//将block赋值给block变量
int (^blk)(int) = ^(int){};
//将block变量赋值给block变量
int (^blk1)(int) = blk;
//两个block变量相互赋值
int (^blk2)(int);
blk2 = blk1;
//在函数参数中使用block类型变量可以向函数通报block
void func((int)(^blk)(int));
//在函数返回值中使用block可以将返回值指定为block
void func(){
return ^{return;};
}
//使用typedef界说block
typedef (int)(^blk)(int);//界说一个block,后面该block的类型就为blk
//通过block类型变量挪用block与在c语言中通常的函数执行没什么区别
blk func(blk block,int rate){
return blk(rate);
}
//这里blk截获的是Array工具的实例指针,通过这个实例指针挪用该工具的方式是完全没问题的,然则若是向Array指针赋值的话就会编译错误(可以用__block解决)
id Array = [NSMutableArray new];
void (^blk)(void) = ^{
id obj = [NSObject new];
[Array addObject:obj];
};
在block中若是需要改变被截获的外部变量的值,可以使用__block说明符(__block存储域类说明符)来解决
block代码转换为cpp代码剖析(待完善)
//block对外部变量捕捉的原理,使用cpp代码查看
//这里写一个block捕捉外部变量val的值
int val = 10;
void (^blk)(void) = ^{
printf("%d",val);
};
//block本质也是一个OC的工具,oc工具都是结构体,其中含有指向父类的isa指针
struct __main_block_impl_0 {
struct __block_impl impl;
struct __main_block_desc_0* Desc;
int val;
__main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, int _val, int flags=0) : val(_val) {
impl.isa = &_NSConcreteStackBlock;
impl.Flags = flags;
impl.FuncPtr = fp;
Desc = desc;
}
};
//这里使用clang -rewrite-objc将.m代码转换成.cpp代码,这里的_cself是block的自身的结构体指针,可以看到在block的函数中是将val重新创建了一个变量举行输出
static void __main_block_func_0(struct __main_block_impl_0 *__cself) {
int val = __cself->val; // bound by copy
printf("%d",val);
}
三种block的形式
NSConcreteGlobalBlock(全局Block,存放在全局区[数据区])
纪录全局变量的地方有Block语法时
Block语法的表达式中不使用应截获的自动变量时
NSConcreteStackBlock(栈Block)
除了1.中的两种情形天生的Block,其他使用Block语法发生的Block都是栈Block
NSConcreteMallocBlock(堆Block)
设置在全局区的block在变量作用域外也可以通过指针平安的接见,然则设置在栈上的block一旦其作用域竣事就会被系统接纳
Block提供了将Block和__Block变量复制到堆上的方式来解决这个问题
复制到堆上的block将类工具NSMallocBlock赋值给isa指针
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 _val, int flags=0) : val(_val) {
//注重这里就是讲isa指针指向堆Block
impl.isa = &_NSConcreteStackBlock;
}
};