盏空间的block 不会对外面capture的变量进行强引用 无论weak修饰 还是strong修饰
堆空间的block 会 对外面capture的变量进行强引用
__weak
修饰后 block结构体中引用对象也会变成 __weak
当对block进行copy操作的
block desc中会添加两个方法
copy会调用block_object_assign
函数
Block_object_assign
自动根据capture到的变量的引用是weak还是strong 来进行操作 类似于retain
在block从堆上移除会调用__main_block_dispose
__main_block_dispose
会调用_Block_object_dispose
。_Block_object_dispose
函数会自动释放引用的变量, 类似release
我们书写下下面代码 然后看一下rewrite-objc 后生成什么
__block NSObject *person = [NSObject new]; void (^testBlock)(void) = ^(void) { NSLog(@"%@",person);// person 为__block结构体中的person};
__attribute__((__blocks__(byref))) __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, ((NSObject *(*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("NSObject"), sel_registerName("new"))};
当被__block
修饰后的persion 会被构造到个结构体__Block_byref_person_0
中
struct __Block_byref_person_0 { void *__isa; // isa __Block_byref_person_0 *__forwarding; //指向自己的指针 当block从栈copy到堆中 则指向堆中block的地址 int __flags; // 标记 int __size; // 大小 void (*__Block_byref_id_object_copy)(void*, void*); // 当block被拷贝到堆中执行此方法 void (*__Block_byref_id_object_dispose)(void*); // 当block释放 执行这个方法 NSObject *person; //persion};
在ARC环境下 block在赋值的时候 会发生拷贝。具体的指向由下图所示。
当__block __weak NSObject *person = [NSObject new];
修饰符为weak时 弱引用 其他时候为强引用
这样的结构的好处是无论我们从栈中去找block找到__forwrding
还是堆中block__forwarding
找person的时候,都能够找到堆中的block 中的person 这样就确保person的存在。
__weak
unsafe_unretain
__block
里面
因为__block
生成的结构体类似中间变量,所以在循环引用个的时候是一个三角结构,我们在在block中将__block
修饰的变量置为nil 既可解决循环引用。如下图