一、block的本质
block本质上也是一个OC对象,它内部也有一个isa指针
block内部代码会封装到_block_func_0函数中,函数地址保存在FuncPtr中
执行block内部代码时是通过FuncPtr找到函数地址进行调用
int age = 10;
void (^block)(void) = ^ {
NSLog(@"%d", age);
};
//block底层结构
struct __block_impl {
void *isa;
int Flags;
int Reserved;
void *FuncPtr;
};
static struct __main_block_desc_0 {
size_t reserved;
size_t Block_size;
}
struct __main_block_impl_0 {
struct __block_impl impl;
struct __main_block_desc_0* Desc;
int age;
//构造函数(类似于OC的init方法),返回结构体对象
__main_block_impl_0(void *fp, struct __main_block_desc_0 *desc,
int _age, int flags=0) : age(_age) {
impl.isa = &_NSConcreteStackBlock;
impl.Flags = flags;
impl.FuncPtr = fp;
Desc = desc;
}
};
二、block的变量捕获机制
为了保证block内部能够正常访问外部的变量,block有个变量捕获机制
变量类型 |
捕获到block内部 |
访问方式 | |
局部变量 |
auto |
YES |
值传递 |
static |
YES |
指针传递 | |
全局变量 |
NO |
直接访问 |
三、解决循环引用问题
解决循环引用问题有三种方案:__weak、__unsafe_unretained、__block
1、__weak:不会产生强引用,指向的对象销毁时,会自动让指针指为nil
__weak typeof(self)weakSelf = self;
self.block = ^ {
printf("%p", weakSelf);
};
2、__unsafe_unretained:不会产生强引用,不安全,指向的对象销毁时,指针存储的地址值不变
__unsafe_unretained id weakSelf = self;
self.block = ^ {
NSLog(@"%p", weakSelf);
}
3、__block:必须要调用block才行
__block QLPerson *person = [[QLPerson alloc] init];
person.age = 10;
person.block = ^ {
NSLog(@"age is %d", person.age);
person = nil;
};
person.block();