美文网首页iOS-blockOC基础OC 底层
《Objective-C高级编程》Blocks 阅读笔记 ite

《Objective-C高级编程》Blocks 阅读笔记 ite

作者: dibadalu | 来源:发表于2016-02-15 23:40 被阅读832次

    《Objective-C高级编程》Blocks 阅读笔记系列

    《Objective-C高级编程》Blocks 阅读笔记 item1(Blocks概要和模式)
    《Objective-C高级编程》Blocks 阅读笔记 item2(Block的实质)
    《Objective-C高级编程》Blocks 阅读笔记 item3(截获自动变量值)
    《Objective-C高级编程》Blocks 阅读笔记 item4(__block说明符)
    《Objective-C高级编程》Blocks 阅读笔记 item5(Block存储域)
    《Objective-C高级编程》Blocks 阅读笔记 item6(__block变量存储域)
    《Objective-C高级编程》Blocks 阅读笔记 item7(截获对象)
    《Objective-C高级编程》Blocks 阅读笔记 item8(__block变量和对象)
    《Objective-C高级编程》Blocks 阅读笔记 item9(Block循环引用)
    《Objective-C高级编程》Blocks 阅读笔记 item10(copy/release实例方法)

    2.3 Blocks的实现

    2.3.1 Block的实质

    Clang(LLVM编译器)具有将含有Block语法的源代码转换为我们可读源代码的功能。通过“-rewrite-objc”选项就能将含有Block语法的源代码变换为C++的源代码(本质是使用了struct结构的C语言源代码)。

    int main()
    {
      void (^blk)(void) = ^{printf("Block\n");};
      blk();
      return 0;
    }
    

    通过clang转换为以下形式:

    // 结构体 __block_impl
    struct __block_impl {
        void *isa;
        int Flags;      // 标志
        int Reserved;   // 今后版本升级所需的区域
        void *FuncPtr;  // 函数指针
    };
    
    
    // 结构体 __main_block_impl_0
    struct __main_block_impl_0 {
        // 成员变量
        struct __block_impl impl; 
        struct __main_block_desc_0* Desc;
        
        // 该结构体的构造函数
        __main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, int flags = 0){
            // _NSConcreteStackBlock用于初始化__block_impl结构体的isa成员
            // (将Block指针赋值给Block的结构体成员变量isa)
            impl.isa = &_NSConcreteStackBlock; 
            impl.Flags = flags;
            impl.FuncPtr = fp;
            Desc = desc;
        }
    };
    
    
    // 最初的源代码中的Block语法经clang变换,被处理成简单的C语言函数(该函数以Block语法所属的函数名——main和该Block语法在该函数出现的顺序值——0来命名)。
    // __ceself为指向Block值的变量。
    static void __main_block_func_0(struct __main_block_impl_0 *__cself)
    {
        printf("Block\n");
    }
    
    // 静态结构体 __main_block_desc_0
    static struct __main_block_desc_0{
        unsigned long reserved;     // 今后版本升级所需的区域
        unsigned long Block_size;   // Block的大小
    } __mian_block_desc_0_DATA = { // 该结构体实例的初始化部分
        0,
        sizeof(struct __main_block_impl_0) // 使用Block(即__main_block_impl_0结构体实例)的大小进行初始化
    };
    
    // main函数,从这里开始阅读源代码
    int main()
    {
        // 调用结构体__main_block_impl_0的构造函数__main_block_impl_0
        void (*blk)(void) =
            (void (*)(void)) & __main_block_impl_0(
                (void *)__main_block_func_0, &__mian_block_desc_0_DATA);
        /*
        去掉转换部分,如下:
        struct __main_block_impl_0 tmp = __main_block_impl_0(__main_block_func_0, &__main_block_desc_0_DATA);
        struct __main_block_impl_0 *blk = &tmp;
        这段代码对应:
        void (^blk)(void) = ^{printf("Block\n");};
        理解:
        1. 将__main_block_impl_0结构体类型的自动变量(即栈上生成的__main_block_impl_0结构体实例的指针)赋值给__main_block_impl_0结构体指针类型的变量blk
        2. __main_block_func_0是由Block语法转换的C语言函数指针。
        3. __main_block_desc_0_DATA作为静态全局变量初始化的__main_block_desc_0结构体实例指针
        4. 将__main_block_impl_0的__block_impl进行展开,__main_block_impl_0结构体根据构造函数会像下面进行初始化:
        isa = &_NSConcreteStackBlock; 
        Flags = 0;
        Reserved = 0;
        FuncPtr = __main_block_func_0;
        Desc = &__main_block_desc_0_DATA;
        */ 
        
        
        ((void (*)(struct __block_impl *))(
            (struct __block_impl *)blk)->FuncPtr) ((struct __block_impl *)blk);
        /*
        去掉转换部分,如下:
        (*blk->impl.FuncPtr)(blk);
        这段代码对应:
        blk();
        理解:
        1. 使用函数指针调用函数
        2. 由Block语法转换的__main_block_func_0函数的指针被赋值成员变量FuncPtr中
        3. __main_block_func_0函数的参数__cself指向Block值,在调用该函数的源代码中可以看出Block正是作为参数进行了传递
        */
        
        return 0;
    }
    

    Block就是Objective-C对象

    在弄清楚Block就是Objective-C对象前,要先理解objc_object结构体和objc_class结构体。

    • id类型是objc_object结构体的指针类型。
     typedef struct objc_object {
            Class isa;
     } *id;
    
    • Class是objc_class结构体的指针类型。
      typedef struct objc_class *Class;
      struct objc_class {
             Class isa;
      } ;
    
    • objc_object结构体和objc_class结构体归根到底是各个对象和类的实现中最基本的结构体。

    *** 如下,通过一个简单的MyObject类来说明Objective-C类与对象的实质:***

    @interface MyObject : NSObject
    {
      int val0;
      int val1;
    }
    

    *** 基于objc_object结构体,该类的对象的结构体如下:***

    struct MyObject {
      Class isa; // 成员变量isa持有该类的结构体实例指针
      int val0;  // 原先MyObject类的实例变量val0和val1被直接声明为成员变量
      int val1;
    }
    

    理解:

    • MyObject类的实例变量val0和val1被直接声明为对象的成员变量。
    • “Objective-C中由类生成对象”意味着,像该结构体这样“生成由该类生成的对象的结构体实例”。
    • 生成的各个对象(即由该类生成的对象的各个结构体实例),通过成员变量isa保持该类的结构体实例指针。


      Snip20160215_13.png

    *** 各类的结构体是基于objc_class结构体的class_t结构体:***

    struct class_t {
      struct class_t *isa;
      struct class_t *superclass;
      Cache cache;
      IMP *vtable;
      uintptr_t data_NEVER_USE;
    }
    

    理解:

    • 在Objective-C中,比如NSObject的class_t结构体实例以及NSMutableArray的class_t结构体实例等,均生成并保持各个类的class_t结构体实例。
    • 该实例持有声明的成员变量、方法的名称、方法的实现(即函数指针)、属性以及父类的指针,并被Objective-C运行时库所使用。

    回到正题——“Block就是Objective-C对象”,*** 先看Block结构体:***

    struct __main_block_impl_0 {
        void *isa;
        int Flags;      // 标志
        int Reserved;   // 今后版本升级所需的区域
        void *FuncPtr;  // 函数指针
        struct __main_block_desc_0* Desc;
    };
    

    理解:

    • 此__main_block_impl_0结构体相当于基于objc_object结构体的Objective-C类的对象的结构体
    • 对其中的isa进行初始化,如
      isa = &_NSConcreteStackBlock;
      
      即_NSConcreteStackBlock相当于class_t结构体实例
    • 在将Block作为Objective-C的对象处理时,关于该类的信息放置于_NSConcreteStackBlock中。

    相关文章

      网友评论

        本文标题:《Objective-C高级编程》Blocks 阅读笔记 ite

        本文链接:https://www.haomeiwen.com/subject/byppkttx.html