iSO底层原理 - Block的本质
2017-08-21 本文已影响0人
南城同學
Block的本质:
- block本质上也是一个OC对象,它内部也有个isa指针;
- block是封装了函数调用以及函数调用环境的OC对象;
Block的数据结构
Block的数据结构block的变量捕获(capture)
-
为了保证block内部能够正常访问外部的变量,block有个变量捕获机制;
1.局部变量需要捕获;
2.全局变量不需要捕获,直接访问就可以。 - 捕获机制
局部变量
// auto:自动变量,离开作用域就销毁
//默认就是auto
auto int age = 10;
static int height = 10;
void (^block)(void) = ^{
// age的值捕获进来(capture)
NSLog(@"age is %d, height is %d", age, height);
};
age = 20;
height = 20;
block();
- 打印结果是:age = 10; height = 20。
- 底层结构如下:
struct __test_block_impl_0 {
struct __block_impl impl;
struct __test_block_desc_0* Desc;
int age;
int *height;
__test_block_impl_0(void *fp, struct __test_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;
}
};
1> 创建block的时候,直接 auto
修饰 的age
封装到了block中了,block外再修改,不会影响block内部的age
;
2> static
修饰的height
,传到block内部的是一个指针;外部修改,也会影响block内部的结果。
为何这样设置 ?
- 因为
auto
修饰的局部变量,离开作用域后就会销毁;如果也采用指针访问,那此时访问到的就是垃圾数据。
扩展 :self 会被捕获吗 ?
- (void)test {
void (^block)(void) = ^{
NSLog(@"-------%p", self);
};
block();
}
- 会;
-
self
其实是一个参数,参数是一个局部变量。
// test函数完整写法如下:
- (void)test(Object *self, SEL _cmd) {
}