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++里面就是传入的是引用
浙公网安备 33010602011771号