什么时候需要对变量使用__block?
__block可以用于解决block内部无法修改auto变量值的问题。__block不能修饰全局变量、静态变量(static)。
__block用来赋值场景(对象类型)(使用场景修改auto变量值)
//赋值场景 NSMutableArray *__block array = nil; void(^Block)(void) = ^{ array = [NSMutableArray array]; }; Block();
使用场景修改auto变量值(基本数据类型)和底层实现
__block int age = 10; __block NSObject *obj = [[NSObject alloc] init]; void (^block)(void) = ^{ obj = nil; age = 20; };
上面的代码会被编译为:
struct __main_block_impl_0 { struct __block_impl impl; struct __main_block_desc_0* Desc; __Block_byref_obj_1 *obj; // by ref __Block_byref_age_0 *age; // by ref __main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, __Block_byref_age_0 *_age, int flags=0) : age(_age->__forwarding) { impl.isa = &_NSConcreteStackBlock; impl.Flags = flags; impl.FuncPtr = fp; Desc = desc; } }; struct __Block_byref_age_0 { void *__isa; __Block_byref_age_0 *__forwarding; int __flags; int __size; int age; }; struct __Block_byref_obj_1 { void *__isa; __Block_byref_obj_1 *__forwarding; int __flags; int __size; //内存管理 void (*__Block_byref_id_object_copy)(void*, void*); void (*__Block_byref_id_object_dispose)(void*); NSObject *obj; }; //实际执行的block代码 static void __main_block_func_0(struct __main_block_impl_0 *__cself) { __Block_byref_obj_1 *obj = __cself->obj; // bound by ref __Block_byref_age_0 *age = __cself->age; // bound by ref (obj->__forwarding->obj) = __null; (age->__forwarding->age) = 20; }
可见,__block修饰的变量会被包装成一个对象。
问题:block在修改NSMutableArray时,需不需要添加__block?
//block里面添加数据 不需要使用__block 因为这是对地址进行的操作 NSMultableArray *array = [NSMultableArray array]; void(^Block)() = ^{ [array addObject:@"1"]; }; Block();
我们给array
添加元素,是使用这个地址,而不是修改这个地址, 但是如果我们array = nil
这样才会报错,所以如果赋值的话需要用__block
__block变量的内存管理
当block在栈上时,并不会对__block变量产生强引用。
当block被copy到堆时:
- 会调用block内部的copy函数
- copy函数内部会调用_Block_object_assign函数
- _Block_object_assign函数会对__block变量形成强引用(retain)[仅ARC, MRC不会retain]
当block从堆中移除时:
- 会调用block内部的dispose函数
- dispose函数内部会调用_Block_object_dispose函数
- _Block_object_dispose函数会自动释放引用的__block变量(release)