iOS block 本质研究
近期在看facebook的retaincycle检查工具的源代码,其中关于block的强引用部分,重新促使又研究了一遍block的代码本质
下面分别对block capture对象的代码进行分析。
源代码1:
#import <Foundation/Foundation.h> @interface Test:NSObject - (void)test; @end @implementation Test - (void)test { NSLog(@"%@",NSStringFromSelector(_cmd)); } @end int main(int argc, const char * argv[]) { @autoreleasepool { Test*t = [[Test alloc] init]; Test*tt = t; void (^blk)(void) = ^{ [tt test]; printf("hello world\n"); }; blk(); } return 0; }
输入命令:clang -rewrite-objc main.m
这个tt变量将会被block capture住,具体看翻译后的代码:
struct __main_block_impl_0 { struct __block_impl impl; struct __main_block_desc_0* Desc; Test *tt; __main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, Test *_tt, int flags=0) : tt(_tt) { impl.isa = &_NSConcreteStackBlock; impl.Flags = flags; impl.FuncPtr = fp; Desc = desc; } }; static void __main_block_func_0(struct __main_block_impl_0 *__cself) { Test *tt = __cself->tt; // bound by copy ((void (*)(id, SEL))(void *)objc_msgSend)((id)tt, sel_registerName("test")); NSLog((NSString *)&__NSConstantStringImpl__var_folders_d5_scznnxt5263gy86pdqg3h5kc0000gn_T_main_d393eb_mi_1); } static void __main_block_copy_0(struct __main_block_impl_0*dst, struct __main_block_impl_0*src) {_Block_object_assign((void*)&dst->tt, (void*)src->tt, 3/*BLOCK_FIELD_IS_OBJECT*/);} static void __main_block_dispose_0(struct __main_block_impl_0*src) {_Block_object_dispose((void*)src->tt, 3/*BLOCK_FIELD_IS_OBJECT*/);} static struct __main_block_desc_0 { size_t reserved; size_t Block_size; void (*copy)(struct __main_block_impl_0*, struct __main_block_impl_0*); void (*dispose)(struct __main_block_impl_0*); } __main_block_desc_0_DATA = { 0, sizeof(struct __main_block_impl_0), __main_block_copy_0, __main_block_dispose_0}; int main(int argc, const char * argv[]) { /* @autoreleasepool */ { __AtAutoreleasePool __autoreleasepool; Test*t = ((Test *(*)(id, SEL))(void *)objc_msgSend)((id)((Test *(*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("Test"), sel_registerName("alloc")), sel_registerName("init")); Test*tt = t; void (*blk)(void) = ((void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA, tt, 570425344)); ((void (*)(__block_impl *))((__block_impl *)blk)->FuncPtr)((__block_impl *)blk); } return 0; }
从代码可以看出tt变量被capture主
__main_block_impl_0这个类的构造函数传入了一个参数tt,是一份copy
__main_block_impl_0的构造函数里面,构造了__main_block_desc_0_DATA这个结构体对象,
__main_block_desc_0_DATA这个结构体对象里面又包含了__main_block_dispose_0这个“析构函数“
它是一个静态函数,析构函数调用了block.h里面的系统函数_Block_object_dispose释放内存
static void __main_block_dispose_0(struct __main_block_impl_0*src) {_Block_object_dispose((void*)src->tt, 3/*BLOCK_FIELD_IS_OBJECT*/);}
这样脉络比较清晰明朗。
下面给变量加上__block修饰一下,看看翻译出来的代码:
struct __Block_byref_tt_0 { void *__isa; __Block_byref_tt_0 *__forwarding; int __flags; int __size; void (*__Block_byref_id_object_copy)(void*, void*); void (*__Block_byref_id_object_dispose)(void*); Test *tt; }; struct __main_block_impl_0 { struct __block_impl impl; struct __main_block_desc_0* Desc; Test *t; __main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, Test *_t, int flags=0) : t(_t) { impl.isa = &_NSConcreteStackBlock; impl.Flags = flags; impl.FuncPtr = fp; Desc = desc; } }; static void __main_block_func_0(struct __main_block_impl_0 *__cself) { Test *t = __cself->t; // bound by copy ((void (*)(id, SEL))(void *)objc_msgSend)((id)t, sel_registerName("test")); NSLog((NSString *)&__NSConstantStringImpl__var_folders_d5_scznnxt5263gy86pdqg3h5kc0000gn_T_main_a684f3_mi_1); } static void __main_block_copy_0(struct __main_block_impl_0*dst, struct __main_block_impl_0*src) {_Block_object_assign((void*)&dst->t, (void*)src->t, 3/*BLOCK_FIELD_IS_OBJECT*/);} static void __main_block_dispose_0(struct __main_block_impl_0*src) {_Block_object_dispose((void*)src->t, 3/*BLOCK_FIELD_IS_OBJECT*/);} static struct __main_block_desc_0 { size_t reserved; size_t Block_size; void (*copy)(struct __main_block_impl_0*, struct __main_block_impl_0*); void (*dispose)(struct __main_block_impl_0*); } __main_block_desc_0_DATA = { 0, sizeof(struct __main_block_impl_0), __main_block_copy_0, __main_block_dispose_0}; int main(int argc, const char * argv[]) { /* @autoreleasepool */ { __AtAutoreleasePool __autoreleasepool; Test*t = ((Test *(*)(id, SEL))(void *)objc_msgSend)((id)((Test *(*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("Test"), sel_registerName("alloc")), sel_registerName("init")); __attribute__((__blocks__(byref))) __Block_byref_tt_0 tt = {(void*)0,(__Block_byref_tt_0 *)&tt, 33554432, sizeof(__Block_byref_tt_0), __Block_byref_id_object_copy_131, __Block_byref_id_object_dispose_131, t}; void (*blk)(void) = ((void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA, t, 570425344)); ((void (*)(__block_impl *))((__block_impl *)blk)->FuncPtr)((__block_impl *)blk); } return 0; }
__Block_byref_tt_0用一个结构体包装了一层,同时__block变量传的是地址,c++里面就是传入的是引用