• 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++里面就是传入的是引用
  • 相关阅读:
    CLR c++/CLI 如何返回多个返回值
    在php 中显示array数据
    MVC已死,该是用MOVE的时候了
    拿到网规证书后,办北京户口的遭遇。
    利亚德股票限售股解禁表
    32位MSSQL数据库备份如何在64位MSSQL数据库上恢复
    利用DNS实现负载均衡
    购买服务器具体和什么参数有关
    简单来总结一下C++与C#之间的区别
    c# 操作DOS ping命令判断与指定主机是否可以通信
  • 原文地址:https://www.cnblogs.com/wxm5558/p/5479600.html
Copyright © 2020-2023  润新知