blocks简介
Blocks是C语言的扩充功能:带有自动变量(局部变量)的匿名函数
匿名函数就是不带名称的函数,在C语言中不允许这种函数存在。在C语言中为了调用函数,必须使用该函数的名称,即使使用函数指针来直接调用函数,虽然似乎不用知道函数名也能够使用该函数,但是其实只是似乎,其实还是需要的,所以就是说在C语言中,不能使用匿名函数这种不带名称的函数
但是当我们有了Blocks,源代码中就能够使用匿名函数,即不带名称的函数
那么带有局部变量是什么意思呢。
书上举了两个例子,当使用C语言的时
使用全局变量来多次调用函数,该变量值总能保持不变所以可以进行调用。
但是多个按钮(可以看作参数)之间的传值的时候就会出现问题,这个时候全局变量也并不能很好的解决,可以使用函数参数传递
在使用C++和Object—C的时候使用类可以保持变量值并多次持有该变量自身,由类生成的实例或对象保持该成员变量的值
但是使用C++或object—C增加了代码长度,所以使用blocks最好啦,blocks又满足条件又简短
block语法
^void (int event) {
printf("buttonId:%d event=%d\n", i, event);
}
block语法和C语言函数定义相比
1.没有函数名 因为它是匿名函数
- 带有“^“ 因为iOS应用程序的源代码中将大量使用Block,所以插入该记号便于查找
Block语法的BN范式
^ 返回值类型 参数列表 表达式
Block语法中可以省略的类型
- 返回值类型:如果表达式中有return语句就使用该返回值的类型,如果没有就使用void类型。表达式中如果有多个return语句时,所有return的返回值类型必须相同。
- 参数列表:如果不使用参数,参数列表也可以省略,比如^void (void) {printf (“blocks”);} 在省略了参数列表以及返回值类型之后^{printf (“blocks”);}
书上说返回值类型和参数列表均被省略的block语法是大家最为熟知的记述吧?
Block类型变量
C语言中,可以将所定义函数的地址赋值给函数指针类型变量中
int (*funcptr)(int) = &func;
在block语法下,一旦使用block语法就相当于生成了可赋值给Block类型变量的“值”
block类型变量与一般的C语言变量完全相同,可作为以下用途使用
自动变量 函数参数 静态变量 静态全局变量 全局变量
声明Block类型变量的示例如下所示
int (^blk) (int);
- 将Block语法赋值给声明为Block类型的变量中
int (^blk) (int) = ^(int count){return count + 1;};
左侧是block声明,右侧是block定义
- 等号左侧的代码表示了这个Block的类型:它接受一个int参数,返回一个int值。
- 等号右侧的代码是这个Block语法:相当于生成了可赋值给Block类型变量的“值”,它是等号左侧定义的block类型的一种实现。
因为通常的变量相同,当然也也可以这样写
int (^blk1)(int) = blk;
int (^blk2)(int);
blk2 = blk1;
- 使用Block类型变量
在函数参数中使用Block类型变量可以向函数传递Block
void func(int (^blk)(int)) {
void func(blk_t blk)
在函数返回值中指定Block类型,可以将Block作为函数返回值返回
int (^func()) (int)
{
return ^(int count){return count + 1;};
}
blk_t func(){
为了简化,我们可以使用typedef来解决问题
typedef int (^blk_t)(int);
通过使用typedef可声明
- 调用Block(函数调用和函数参数)
将赋值给Block类型变量中的Block方法像C语言通常的函数调用那样使用,这种方法与使用函数指针类型变量调用函数的方法几乎完全相同
int result = (*funcptr)(10);
int result = blk(10);
在函数参数中使用Block类型变量并在函数中执行Block的例子如下:
int func(blk_t blk, int rate)
{
return blk(rate);
}
- (int) methodUsingBlock:(blk_t)blk rate:(int)rate
{
return blk(rate);
}
- Block指针类型变量
blk_t *blkptr = &blk;
iOS中Block的用法,举例,解析与底层原理(这可能是最详细的Block解析) - CocoaChina_一站式开发者成长社区
可以参考这篇文章中Block的常见用法以及语法总结(声明及定义语法),写的非常的好
Block的本质
block本质也是一个OC对象,封装了函数调用和函数调用环境
int main(int argc, const char * argv[]) {
@autoreleasepool {
void (^block)(void) = ^{
NSLog(@"132314234");
};
block();
}
return 0;
}
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;
}
};
static void __main_block_func_0(struct __main_block_impl_0 *__cself) {
NSLog((NSString *)&__NSConstantStringImpl__var_folders_p__1kwt86gs28xdwnz5cds254400000gn_T_main_bf9aba_mi_0);
}
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)};
int main(int argc, const char * argv[]) {
{ __AtAutoreleasePool __autoreleasepool;
void (*block)(void) = &__main_block_impl_0(
__main_block_func_0,
&__main_block_desc_0_DATA);
block->FuncPtr(block);
}
return 0;
}
static struct IMAGE_INFO { unsigned version; unsigned flag; } _OBJC_IMAGE_INFO = { 0, 2 };
block指向__main_block_impl_0 ,看__main_block_impl_0 返回什么,它返回一个结构体
__main_block_impl_0 是一个结构体,在结构体里面有一个构造函数(不用返回值,C++中参数有默认值可以不传值),初始化,将参数赋给结构体中struct __block_impl impl 和struct __main_block_desc_0* Desc ,最终返回一个结构体
__main_block_func_0 是一个函数,在__main_block_impl_0 中将这个函数的地址传给了fp参数,fp参数继续传给了__main_block_impl_0 中的FuncPtr
struct __main_block_desc_0* Desc 指向struct __main_block_desc_0 这个结构体,这个结构体计算block的大小
最后通过funcPtr调用__main_block_func_0 函数,将Block地址传进去执行Block代码
Block截获变量
先上图 
对局部变量的截获
局部变量:
它是自动对象(auto),只在函数执行期间存在,离开作用域就销毁 截获方式为值截获
int main(int argc, const char * argv[]) {
@autoreleasepool {
int a;
void (^block)(void) = ^{
NSLog(@"a = %d", a);
};
block();
}
return 0;
}
struct __main_block_impl_0 {
struct __block_impl impl;
struct __main_block_desc_0* Desc;
int a;
__main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, int _a, int flags=0) : a(_a) {
impl.isa = &_NSConcreteStackBlock;
impl.Flags = flags;
impl.FuncPtr = fp;
Desc = desc;
}
};
int a;
void (*block)(void) = ((void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA, a));
静态局部变量:
只对定义自己的函数体始终可见,截获方式为指针截获
int main(int argc, const char * argv[]) {
@autoreleasepool {
static int a;
void (^block)(void) = ^{
NSLog(@"a = %d", a);
};
block();
}
return 0;
}
struct __main_block_impl_0 {
struct __block_impl impl;
struct __main_block_desc_0* Desc;
int *a;
__main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, int *_a, int flags=0) : a(_a) {
impl.isa = &_NSConcreteStackBlock;
impl.Flags = flags;
impl.FuncPtr = fp;
Desc = 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)};
int main(int argc, const char * argv[]) {
{ __AtAutoreleasePool __autoreleasepool;
static int a;
void (*block)(void) = ((void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA, &a));
((void (*)(__block_impl *))((__block_impl *)block)->FuncPtr)((__block_impl *)block);
}
return 0;
}
对象类型:
Block对对象类型的auto变量的截获,重点是对象类型 
typedef void (^MyBlock)(void);
int main(int argc, const char * argv[]) {
@autoreleasepool {
MJPerson *person = [[MJPerson alloc] init];
MyBlock block = ^{
NSLog(@"%p", person);
};
block();
}
return 0;
}
C++
static void __main_block_copy_0(struct __main_block_impl_0*dst, struct __main_block_impl_0*src) {_Block_object_assign((void*)&dst->person, (void*)src->person, 3);}
static void __main_block_dispose_0(struct __main_block_impl_0*src) {_Block_object_dispose((void*)src->person, 3);}
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};
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)};
MyBlock block = ((void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA, (__Block_byref_weakPerson_0 *)&weakPerson, 570425344));
int main(int argc, const char * argv[]) {
@autoreleasepool {
MJPerson *person = [[MJPerson alloc] init];
__block __weak MJPerson *weakPerson = person;
MyBlock block = ^{
NSLog(@"%p", weakPerson);
};
block();
}
return 0;
}
static void __main_block_copy_0(struct __main_block_impl_0*dst, struct __main_block_impl_0*src)
{_Block_object_assign((void*)&dst->weakPerson, (void*)src->weakPerson, 8);}
static void __main_block_dispose_0(struct __main_block_impl_0*src) {_Block_object_dispose((void*)src->weakPerson, 8);}
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};
MyBlock block = ((void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA, (__Block_byref_weakPerson_0 *)&weakPerson, 570425344));
- 用我自己通俗一点的话来说就是:
我们在上面也可以看到,对比之前的auto变量和静态局部变量,多了两个copy和dispose函数 如果Block访问的是对象类型,就会自动生成copy和dispose函数,来对对象进行内存原理 如果Block访问的是自动变量auto,就没有这两个函数 在对象类型中有__strong 和__weak 两种修饰符,给当地进行初始化和废弃,为此需要增加成员变量copy和dispose 但是auto自动变量就用不到,所以它也没有copy和dispose这两个函数 
Block对__block变量的截获
在有__block修饰符的时候,当Blockcopy到堆上时,会把__block也copy到堆上,即Block对__block的截获。  对于__block变量的截获,同样会调用copy和dispose函数。
typedef void (^MyBlock)(void);
int main(int argc, const char * argv[]) {
@autoreleasepool {
MJPerson __block *person = [[MJPerson alloc] init];
MyBlock block = ^{
NSLog(@"%p", person);
};
block();
}
return 0;
}
typedef void (*MyBlock)(void);
struct __Block_byref_person_0 {
void *__isa;
__Block_byref_person_0 *__forwarding;
int __flags;
int __size;
void (*__Block_byref_id_object_copy)(void*, void*);
void (*__Block_byref_id_object_dispose)(void*);
MJPerson *__strong person;
};
struct __main_block_impl_0 {
struct __block_impl impl;
struct __main_block_desc_0* Desc;
__Block_byref_person_0 *person;
__main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, __Block_byref_person_0 *_person, int flags=0) : person(_person->__forwarding) {
impl.isa = &_NSConcreteStackBlock;
impl.Flags = flags;
impl.FuncPtr = fp;
Desc = desc;
}
};
static void __main_block_func_0(struct __main_block_impl_0 *__cself) {
__Block_byref_person_0 *person = __cself->person;
NSLog((NSString *)&__NSConstantStringImpl__var_folders_p__1kwt86gs28xdwnz5cds254400000gn_T_main_080995_mi_0, (person->__forwarding->person));
}
static void __main_block_copy_0(struct __main_block_impl_0*dst, struct __main_block_impl_0*src) {_Block_object_assign((void*)&dst->person, (void*)src->person, 8);}
static void __main_block_dispose_0(struct __main_block_impl_0*src) {_Block_object_dispose((void*)src->person, 8);}
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};
int main(int argc, const char * argv[]) {
{ __AtAutoreleasePool __autoreleasepool;
__Block_byref_person_0 person = {(void*)0,(__Block_byref_person_0 *)&person, 33554432, sizeof(__Block_byref_person_0), __Block_byref_id_object_copy_131, __Block_byref_id_object_dispose_131, ((MJPerson *(*)(id, SEL))(void *)objc_msgSend)((id)((MJPerson *(*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("MJPerson"), sel_registerName("alloc")), sel_registerName("init"))};
MyBlock block = ((void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA, (__Block_byref_person_0 *)&person, 570425344));
((void (*)(__block_impl *))((__block_impl *)block)->FuncPtr)((__block_impl *)block);
}
return 0;
}
static struct IMAGE_INFO { unsigned version; unsigned flag; } _OBJC_IMAGE_INFO = { 0, 2 };
另外我们要注意当block被copy到栈上时,对__block变量一直都是强引用
int main(int argc, const char * argv[]) {
@autoreleasepool {
MJPerson *person = [[MJPerson alloc] init];
__block MJPerson *weakperson = person;
MyBlock block = ^{
NSLog(@"%p", weakperson);
};
block();
}
return 0;
}
struct __Block_byref_weakperson_0 {
void *__isa;
__Block_byref_weakperson_0 *__forwarding;
int __flags;
int __size;
void (*__Block_byref_id_object_copy)(void*, void*);
void (*__Block_byref_id_object_dispose)(void*);
MJPerson *__strong weakperson;
};
对象类型的auto变量、__block变量的对比
他们都调用了copy和dispose函数,不过这两个函数在被它们调用的时候有细微的差别。 
对全局变量的截获
全局变量,不截获,直接取值
int main(int argc, const char * argv[]) {
@autoreleasepool {
int age = 10;
static int height = 10;
void (^block)(void) = ^{
NSLog(@"age = %d, height = %d", age, height);
};
age = 20;
height = 20;
block();
}
return 0;
}
age = 10, height = 20
C++
struct __main_block_impl_0 {
struct __block_impl impl;
struct __main_block_desc_0* Desc;
int age;
int *height;
__main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, int _age, int *_height, int flags=0) : age(_age), height(_height) {
impl.isa = &_NSConcreteStackBlock;
impl.Flags = flags;
impl.FuncPtr = fp;
Desc = desc;
}
};
static void __main_block_func_0(struct __main_block_impl_0 *__cself) {
int age = __cself->age;
int *height = __cself->height;
NSLog((NSString *)&__NSConstantStringImpl__var_folders_p__1kwt86gs28xdwnz5cds254400000gn_T_main_023eda_mi_0, age, (*height));
}
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)};
int main(int argc, const char * argv[]) {
{ __AtAutoreleasePool __autoreleasepool;
int age = 10;
static int height = 10;
void (*block)(void) = ((void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA,
age, &height));
age = 20;
height = 20;
((void (*)(__block_impl *))((__block_impl *)block)->FuncPtr)((__block_impl *)block);
}
return 0;
}
int age_ = 10;
static int height_ = 10;
int main(int argc, const char * argv[]) {
@autoreleasepool {
void (^block)(void) = ^{
NSLog(@"age = %d, height = %d", age_, height_);
};
age_ = 20;
height_ = 20;
block();
}
return 0;
}
int age_ = 10;
int height_ = 10;
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;
}
};
static void __main_block_func_0(struct __main_block_impl_0 *__cself) {
NSLog((NSString *)&__NSConstantStringImpl__var_folders_p__1kwt86gs28xdwnz5cds254400000gn_T_main_a9b1b8_mi_0, age_, height_);
}
((void (*)(__block_impl *))((__block_impl *)block)->FuncPtr)((__block_impl *)block);
Block的三种类型
Block存储域
- _NSConcreteStackBlock类,存储域:栈
- _NSConcreteGlobalBlock类,存储域:数据区
- _NSConcreteMallocBlock类,存储域:堆

Block类型存在的环境
MRC:  1. _NSConcreteGlobalBlock类,存储域:数据区 没有截取的情况即没有访问auto变量(全局变量)?(静态局部变量)
静态局部变量

全局变量  2. _NSConcreteStackBlock类,存储域:栈 一般是访问了局部变量(auto),但是因为随时可能会回收所以很多时候都要Block 下图因为是在ARC情况下,它自动copy了,所以在堆上(Malloc)  3. _NSConcreteMallocBlock类,存储域:堆 栈上的copy到堆 如上图
ARC下一般直接就是Malloc或者Global,因为自动copy了
- 全局变量(即没有访问auto变量的)都是Global
- 局部变量(auto)一般自动进行copy后到堆上(Malloc)
- copy之后,Global还是Global,Stack变为Malloc。Malloc引用计数增加
复制(copy)效果

在ARC环境下,编译器会根据情况自动将栈上的block复制到堆上
比如以下情况
- block作为函数返回值时
- 将block赋值给__strong指针时
- block作为Cocoa API中方法名含有usingBlock的方法参数时
- block作为GCD API的方法参数时
- block作为返回值时

- 将block赋值给__strong指针时

__Block说明符
修饰auto变量
__block修饰auto变量,解决Block内部不能修改auto变量的值的问题 编译器会将__block包装为一个对象
typedef void (^MyBlock)(void);
int main(int argc, const char * argv[]) {
@autoreleasepool {
__block int a = 10;
MyBlock block = ^{
a = 20;
NSLog(@"--%d", a);
};
block();
}
return 0;
}
typedef void (*MyBlock)(void);
struct __Block_byref_a_0 {
void *__isa;
__Block_byref_a_0 *__forwarding;
int __flags;
int __size;
int a;
};
struct __main_block_impl_0 {
struct __block_impl impl;
struct __main_block_desc_0* Desc;
__Block_byref_a_0 *a;
__main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, __Block_byref_a_0 *_a, int flags=0) : a(_a->__forwarding) {
impl.isa = &_NSConcreteStackBlock;
impl.Flags = flags;
impl.FuncPtr = fp;
Desc = desc;
}
};
static void __main_block_func_0(struct __main_block_impl_0 *__cself) {
__Block_byref_a_0 *a = __cself->a;
(a->__forwarding->a) = 20;
NSLog((NSString *)&__NSConstantStringImpl__var_folders_p__1kwt86gs28xdwnz5cds254400000gn_T_main_7a7b85_mi_0, (a->__forwarding->a));
}
static void __main_block_copy_0(struct __main_block_impl_0*dst, struct __main_block_impl_0*src) {_Block_object_assign((void*)&dst->a, (void*)src->a, 8);}
static void __main_block_dispose_0(struct __main_block_impl_0*src) {_Block_object_dispose((void*)src->a, 8);}
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};
int main(int argc, const char * argv[]) {
{ __AtAutoreleasePool __autoreleasepool;
__attribute__((__blocks__(byref))) __Block_byref_a_0 a = {(void*)0,(__Block_byref_a_0 *)&a, 0, sizeof(__Block_byref_a_0), 10};
__Block_byref_a_0 a = {0,
&a,
0,
sizeof(__Block_byref_a_0),
1};
MyBlock block = ((void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA, (__Block_byref_a_0 *)&a, 570425344));
((void (*)(__block_impl *))((__block_impl *)block)->FuncPtr)((__block_impl *)block);
}
return 0;
}
__main_block_impl_0 中有__Block_byref_a_0 *a ,__block对象Block内部通过指针指向age。在__main_block_func_0 中通过指向自己的指针(a->__forwarding->a )修改age,最后修改成功
在此有个forwarding指针需要解释一下 __forwaring在复制之前也就是__block变量配置在栈上的时候 指向的是__Block_byref_val_0 结构体 也就是指向自身 复制之后到了栈上之后就指向了堆上的__block变量 通过__forwaring可以保证无论是在Block外使用__block变量 还是__block变量在栈上堆上 都可以顺利访问同一个__block变量 
被__block修饰的对象类型

int main(int argc, const char * argv[]) {
@autoreleasepool {
MJPerson *person = [[MJPerson alloc] init];
__block MJPerson *blockperson = person;
MyBlock block = ^{
NSLog(@"%p", blockperson);
};
block();
}
return 0;
}
typedef void (*MyBlock)(void);
struct __Block_byref_blockperson_0 {
void *__isa;
__Block_byref_blockperson_0 *__forwarding;
int __flags;
int __size;
void (*__Block_byref_id_object_copy)(void*, void*);
void (*__Block_byref_id_object_dispose)(void*);
MJPerson *__strong blockperson;
};
struct __main_block_impl_0 {
struct __block_impl impl;
struct __main_block_desc_0* Desc;
__Block_byref_blockperson_0 *blockperson;
__main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, __Block_byref_blockperson_0 *_blockperson, int flags=0) : blockperson(_blockperson->__forwarding) {
impl.isa = &_NSConcreteStackBlock;
impl.Flags = flags;
impl.FuncPtr = fp;
Desc = desc;
}
};
static void __main_block_func_0(struct __main_block_impl_0 *__cself) {
__Block_byref_blockperson_0 *blockperson = __cself->blockperson;
NSLog((NSString *)&__NSConstantStringImpl__var_folders_p__1kwt86gs28xdwnz5cds254400000gn_T_main_499baa_mi_0, (blockperson->__forwarding->blockperson));
}
static void __main_block_copy_0(struct __main_block_impl_0*dst, struct __main_block_impl_0*src) {_Block_object_assign((void*)&dst->blockperson, (void*)src->blockperson, 8);}
static void __main_block_dispose_0(struct __main_block_impl_0*src) {_Block_object_dispose((void*)src->blockperson, 8);}
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};
int main(int argc, const char * argv[]) {
{ __AtAutoreleasePool __autoreleasepool;
MJPerson *person = ((MJPerson *(*)(id, SEL))(void *)objc_msgSend)((id)((MJPerson *(*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("MJPerson"), sel_registerName("alloc")), sel_registerName("init"));
__attribute__((__blocks__(byref))) __Block_byref_blockperson_0 blockperson = {(void*)0,(__Block_byref_blockperson_0 *)&blockperson, 33554432, sizeof(__Block_byref_blockperson_0), __Block_byref_id_object_copy_131, __Block_byref_id_object_dispose_131, person};
MyBlock block = ((void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA, (__Block_byref_blockperson_0 *)&blockperson, 570425344));
((void (*)(__block_impl *))((__block_impl *)block)->FuncPtr)((__block_impl *)block);
}
return 0;
}
static struct IMAGE_INFO { unsigned version; unsigned flag; } _OBJC_IMAGE_INFO = { 0, 2 };
__Block_byref_obj1_0 obj1 = {0,
&obj1,
33554432,
sizeof(__Block_byref_obj1_0),
__Block_byref_id_object_copy_131,
__Block_byref_id_object_dispose_131,
obj};
Blk blk1 = &__main_block_impl_0(__main_block_func_0,
&__main_block_desc_0_DATA,
(__Block_byref_obj1_0 *)&obj1,
570425344);
(blk1->FuncPtr)(blk1);
我觉得有个博主这一段解释的很好,引用过来 在这一过程中
- Block截获__block变量,结构体中生成了指向__block变量的指针;
- 而__block修饰的是一个对象类型的变量,即__block结构体中有一个对象类型的指针变量;
- __block以及Block最初都在栈上,栈上的Block只是使用栈上的__Block变量,并不持有。 当Block复制到了堆上,截获的__block也会复制到堆上,通过Block的__main_block_copy_0、__main_block_dispose_0函数对__block进行相应的持有和释放。(上面这一段可以参考之前对局部变量的截获中对_block变量截获的内容)
- 当__block复制到了堆上,那么就会使用__block中的__Block_byref_id_object_copy、__Block_byref_id_object_dispose并且根据对象类型的所有权修饰符(weak、strong)进行相应的强引用、弱引用、以及释放
- 对象类型被__weak修饰,那么复制到堆上的__block会调用__Block_byref_id_object_copy持有对象的弱引用。对象类型被__strong修饰,那么复制到堆上的__block会调用__Block_byref_id_object_assign持有对象的强引用。
- 堆上的__block被废弃时,若原来持有对象,使用__Block_byref_id_object_dispose释放所持有的对象。
避免循环引用
一个对象中强引用了block,在block中又使用了该对象,就会发生循环引用。 将该对象使用__weak或者__block修饰符修饰之后再在block中使用。 可以看这里Blocks实现里的循环引用
|