zoukankan      html  css  js  c++  java
  • iOS block原理研究

    研究下block的具体实现,网上已经有过了,自己重新做下,也算是加深理解。

    int main(int argc, const char * argv[]) {

        @autoreleasepool {

            __block int age = 10;

            NSString *name = @"张三";

            void (^block)() = ^{

                int  a = 10;

                int b = 20;

                int c ;

                c =  a + b;

               NSLog(@"name %@",name);

                NSLog(@"age %d",age);

            };

            age  = 30;

            block();//10

    }

    终端中切换到项目的.m文件路径,执行  clang -rewrite-objc main.m ,会得到一个对应的main.cpp文件,文件蛮大,3M多,直接到文件的最后,会看到这样的代码

    struct __main_block_impl_0 {
    struct __block_impl impl;
    struct __main_block_desc_0* Desc;
    NSString *name;
    int age;
    __main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, NSString *_name, int _age, int flags=0) : name(_name), age(_age) {
    impl.isa = &_NSConcreteStackBlock;
    impl.Flags = flags;
    impl.FuncPtr = fp;
    Desc = desc;
    }
    };
    static void __main_block_func_0(struct __main_block_impl_0 *__cself) {
    NSString *name = __cself->name; // bound by copy
    int age = __cself->age; // bound by copy


    int a = 10;
    int b = 20;

    int c ;
    c = a + b;

    NSLog((NSString *)&__NSConstantStringImpl__var_folders_9p_zm9fm86j06j4ng_47_8jbbd40000gn_T_main_1ce142_mi_1,name);

    NSLog((NSString *)&__NSConstantStringImpl__var_folders_9p_zm9fm86j06j4ng_47_8jbbd40000gn_T_main_1ce142_mi_2,age);
    }
    static void __main_block_copy_0(struct __main_block_impl_0*dst, struct __main_block_impl_0*src) {_Block_object_assign((void*)&dst->name, (void*)src->name, 3/*BLOCK_FIELD_IS_OBJECT*/);}

    static void __main_block_dispose_0(struct __main_block_impl_0*src) {_Block_object_dispose((void*)src->name, 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;

    int age = 10;
    NSString *name = (NSString *)&__NSConstantStringImpl__var_folders_9p_zm9fm86j06j4ng_47_8jbbd40000gn_T_main_1ce142_mi_0;
    void (*block)() = ((void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA, name, age, 570425344));
    age = 30;
    ((void (*)(__block_impl *))((__block_impl *)block)->FuncPtr)((__block_impl *)block); //block的执行

    }
    return 0;
    }
    static struct IMAGE_INFO { unsigned version; unsigned flag; } _OBJC_IMAGE_INFO = { 0, 2 };

    其中 __block_impl 是一个block的内部结构,定义如下:

    struct __block_impl {
    void *isa;
    int Flags;
    int Reserved;
    void *FuncPtr;
    };

    每个block会生成对应的结构体__main_block_impl_0 ,其中有个构造函数如下,

     __main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, NSString *_name, int _age, int flags=0) : name(_name), age(_age)

     block内部访问的外部变量在这里都是值类型,看到这里应该很明白了吧!这也是为什么在block体里不能对外部变量进行修改。

    如果要修改,需要加上__block,__block int age = 10,在看

    struct __Block_byref_age_0 {
    void *__isa;
    __Block_byref_age_0 *__forwarding;
    int __flags;
    int __size;
    int age;
    };

    struct __main_block_impl_0 {
    struct __block_impl impl;
    struct __main_block_desc_0* Desc;
    NSString *name;
    __Block_byref_age_0 *age; // by ref
    __main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, NSString *_name, __Block_byref_age_0 *_age, int flags=0) : name(_name), age(_age->__forwarding) {
    impl.isa = &_NSConcreteStackBlock;
    impl.Flags = flags;
    impl.FuncPtr = fp;
    Desc = desc;
    }
    };
    static void __main_block_func_0(struct __main_block_impl_0 *__cself) {
    __Block_byref_age_0 *age = __cself->age; // bound by ref
    NSString *name = __cself->name; // bound by copy


    int a = 10;
    int b = 20;

    int c ;
    c = a + b;

    NSLog((NSString *)&__NSConstantStringImpl__var_folders_9p_zm9fm86j06j4ng_47_8jbbd40000gn_T_main_f23869_mi_1,name);

    NSLog((NSString *)&__NSConstantStringImpl__var_folders_9p_zm9fm86j06j4ng_47_8jbbd40000gn_T_main_f23869_mi_2,(age->__forwarding->age));
    }
    static void __main_block_copy_0(struct __main_block_impl_0*dst, struct __main_block_impl_0*src) {_Block_object_assign((void*)&dst->name, (void*)src->name, 3/*BLOCK_FIELD_IS_OBJECT*/);_Block_object_assign((void*)&dst->age, (void*)src->age, 8/*BLOCK_FIELD_IS_BYREF*/);}

    static void __main_block_dispose_0(struct __main_block_impl_0*src) {_Block_object_dispose((void*)src->name, 3/*BLOCK_FIELD_IS_OBJECT*/);_Block_object_dispose((void*)src->age, 8/*BLOCK_FIELD_IS_BYREF*/);}

    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;

    __attribute__((__blocks__(byref))) __Block_byref_age_0 age = {(void*)0,(__Block_byref_age_0 *)&age, 0, sizeof(__Block_byref_age_0), 10};
    NSString *name = (NSString *)&__NSConstantStringImpl__var_folders_9p_zm9fm86j06j4ng_47_8jbbd40000gn_T_main_f23869_mi_0;
    void (*block)() = ((void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA, name, (__Block_byref_age_0 *)&age, 570425344));
    (age.__forwarding->age) = 30;
    ((void (*)(__block_impl *))((__block_impl *)block)->FuncPtr)((__block_impl *)block);
    }
    return 0;
    }
    static struct IMAGE_INFO { unsigned version; unsigned flag; } _OBJC_IMAGE_INFO = { 0, 2 };

    在这里可以看到,对加了block的外部变量会生成其对应的__Block_byref_age_0,传递的参数也变成了地址(__Block_byref_age_0 *)&age,变成了引用类型, 这样当外部变量被修改后,block中也被修改。

  • 相关阅读:
    c# 发送邮件笔记(一)
    windows API(一)
    SubSonic3.0安装
    Node.js安装MongoDB驱动
    JDBC连接数据库方法
    Delphi LiveBindings如何绑定一个对象(二)(转)
    delphi RTTI机制学习(一)
    Delphi LiveBinds组件
    mysql 每个分类各取5条
    mysql in(...) 1次取出当前记录及上1条下1条记录, 且使用了主键作为索引
  • 原文地址:https://www.cnblogs.com/menchao/p/5238726.html
Copyright © 2011-2022 走看看