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
");
        };
        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++里面就是传入的是引用
原文地址:https://www.cnblogs.com/wxm5558/p/5479600.html