__block修饰符
- __block可以用于解决block内部无法修改auto变量值的问题
- __block不能修饰全局变量、静态变量(static)
- 编译器会将__block变量包装成一个对象
示例1:__block修饰auto常量时
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
| __block int age = 10; ^{ NSLog(@"age is %d", age); }();
struct __block_impl { void *isa; int Flags; int Reserved; void *FuncPtr; };
struct __main_block_desc_0 { size_t reserved; size_t Block_size; void (*copy)(void); void (*dispose)(void); };
struct __Block_byref_age_0 { void *__isa; __Block_byref_age_0 *__forwarding; int __flags; int __size; int age; };
struct __main_block_impl_0 { struct __block_impl impl; struct __main_block_desc_0* Desc; NSObject *p; __Block_byref_age_0 *age; __main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, NSObject *_p, __Block_byref_age_0 *_age, int flags=0) : p(_p), age(_age->__forwarding) { impl.isa = &_NSConcreteStackBlock; impl.Flags = flags; impl.FuncPtr = fp; Desc = desc; } };
|
示例1:__block修饰对象时
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
| Person *person = [[Person alloc] init]; Block block = ^{ NSLog(@"%p", person); }; block();
struct __block_impl { void *isa; int Flags; int Reserved; void *FuncPtr; };
struct __main_block_desc_0 { size_t reserved; size_t Block_size; void (*copy)(void); void (*dispose)(void); };
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*); Person *__weak weakPerson; };
struct __main_block_impl_0 { struct __block_impl impl; struct __main_block_desc_0* Desc; __Block_byref_weakPerson_0 *weakPerson; __main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, __Block_byref_weakPerson_0 *_weakPerson, int flags=0) : weakPerson(_weakPerson->__forwarding) { impl.isa = &_NSConcreteStackBlock; impl.Flags = flags; impl.FuncPtr = fp; Desc = desc; } };
|
__block的内存管理
- 当block在栈上时,并不会对__block变量产生强引用
- 当block被copy到堆时
- 会调用block内部的copy函数
- copy函数内部会调用_Block_object_assign函数
- _Block_object_assign函数会对__block变量形成强引用(retain)
- 当block从堆中移除时
- 会调用block内部的dispose函数
- dispose函数内部会调用_Block_object_dispose函数
- _Block_object_dispose函数会自动释放引用的__block变量(release)
__block的__forwarding指针
- 在栈上的话,__forwarding指向自己
- 在堆上的话,__forwarding指向复制到堆上的的__block变量结构体的指针
对象类型的auto变量、__block变量
- 当block在栈上时,对它们都不会产生强引用
- 当block拷贝到堆上时,都会通过copy函数来处理它们
- __block变量(假设变量名叫做a)
- _Block_object_assign((void*)&dst->a, (void*)src->a, 8/BLOCK_FIELD_IS_BYREF/);
- 对象类型的auto变量(假设变量名叫做p)
- _Block_object_assign((void*)&dst->p, (void*)src->p, 3/BLOCK_FIELD_IS_OBJECT/);
- 当block从堆上移除时,都会通过dispose函数来释放它们
- __block变量(假设变量名叫做a)
- _Block_object_dispose((void*)src->a, 8/BLOCK_FIELD_IS_BYREF/);
- 对象类型的auto变量(假设变量名叫做p)
- _Block_object_dispose((void*)src->p, 3/BLOCK_FIELD_IS_OBJECT/);
被__block修饰的对象类型
- 当__block变量在栈上时,不会对指向的对象产生强引用
- 当__block变量被copy到堆时
- 会调用__block变量内部的copy函数
- copy函数内部会调用_Block_object_assign函数
- _Block_object_assign函数会根据所指向对象的修饰符(__strong、__weak、__unsafe_unretained)做出相应的操作,形成强引用(retain)或者弱引用(
注意:这里仅限于ARC时会retain,MRC时不会retain )
- 如果__block变量从堆上移除
- 会调用__block变量内部的dispose函数
- dispose函数内部会调用_Block_object_dispose函数
- _Block_object_dispose函数会自动释放指向的对象(release)
循环引用问题
解决循环引用问题 - ARC
用__weak、__unsafe_unretained解决
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| __weak typeof(self) weakSelf = self; self.block = ^{ NSLog(@"%p", weakSelf); };
__unsafe_unretained id weakSelf = self; self.block = ^{ NSLog(@"%p", weakSelf); };
注:
|
用__block解决(必须要调用block)
1 2 3 4 5 6
| __block id weakSelf = self; self.block = ^{ NSLog(@"%p", weakSelf); weakSelf = nil; }; self.block()
|
参考