美文网首页
Block结构分析

Block结构分析

作者: 简_爱SimpleLove | 来源:发表于2018-10-17 16:57 被阅读10次

    将Xcode中文件转换为C++文件

    第一步:打开终端,输入xcodebuild -showsdks 展示sdks,找到最新的模拟器型号:


    image.png

    第二步:cd到我们需要转换的文件所在的文件夹,注意只是cd到工程是不行的。
    比如我们想要转换ViewController.m,必须要cd到这个文件夹才行,不然就提示找不到文件:


    image.png
    第三步:输入转换的命令即可,注意要把里面模拟器的型号和文件换成你自己的
    转换成C++代码命令:xcrun -sdk iphonesimulator12.0 clang -rewrite-objc ViewController.m

    包含weak类型数据转换成C++:xcrun -sdk iphonesimulator12.0 clang -S -rewrite-objc -fobjc-arc -fobjc-runtime=ios-12.0 BlockMemoryViewController.m

    最后在你的文件夹下面就会多一个cpp文件。大功告成。

    将OC中block转为C++代码

    在.m文件中写多个不同的block,然后在按照上面的方法,转为C++的代码。.m文件如下:

    #import "BlockStructureViewController.h"
    
    typedef void(^eocblock)(void);
    @interface BlockStructureViewController () {
        UILabel *label;
        eocblock instanceBlock;
    }
    @end
    
    @implementation BlockStructureViewController
    
    /**
     1、空的block
     2、包含简单类型(如int型)block
     3、包含临时的objc对象的block
     4、成员变量(objc)
     5、包含__block的变量
     6、global value
     7、全局static value
     8、局部static value
     */
    
    //block结构:xcrun -sdk iphonesimulator12.0 clang -S -rewrite-objc -fobjc-arc -fobjc-runtime=ios-12.0 BlockStructureViewController.m
    
    int globalValueOne = 10;
    static int staticValue = 5;
    
    - (void)viewDidLoad {
        
        [super viewDidLoad];
        self.view.backgroundColor = [UIColor whiteColor];
        
    }
    
    - (void)emptyBlockFunction {
        
        void (^emptyBlock)(void) = ^{
            NSLog(@"八点钟学院");
        };
        emptyBlock();
    }
    
    - (void)simpleDataBlockFunction {
        
        int i = 10;
        void (^simpleDataBlock)(void) = ^{
            NSLog(@"八点钟学院 %d", i);
        };
        
        simpleDataBlock();
    }
    
    - (void)objcDataBlockFunction {
        UILabel *tmpLabel = [[UILabel alloc] init];
        void (^objcDataBlock)(void) = ^{
            NSLog(@"八点钟学院, %@", tmpLabel);
        };
        objcDataBlock();
    }
    
    - (void)classDataBlockFunction {
        void (^classDataBlock)(void) = ^{
            NSLog(@"八点钟学院 %@", label);
        };
        classDataBlock();
    }
    
    - (void)blockDataBlockFunction {
        
        __block int a = 100;  //a在栈里
        void (^blockDataBlock)(void) = ^{
            // block会将a存放在堆区(栈区的a指向堆区的a,堆区的a指向自己,所以实际上是同一个a)
            a = 1000; //在堆区修改a的值
            NSLog(@"八点钟学院, %d", a);
        };  //blockDataBlock 在堆区
        a = 10; //在栈区修改a的值
        blockDataBlock();
        NSLog(@"栈区a = %d", a);
    }
    
    - (void)globalDataBlockFunction {
        
        void (^globalDataBlock)(void) = ^{
            NSLog(@"八点钟学院 %d", globalValueOne);
        };
        globalDataBlock();
    }
    
    - (void)staticDataBlockFunction {
        
        void (^staticDataBlock)(void) = ^{
            NSLog(@"八点钟学院 %d", staticValue);
        };
        
        staticDataBlock();
    }
    
    - (void)tmpStaticDataBlockFunction {
        
        static int b = 11;
        instanceBlock = ^{
            b = 110;
            NSLog(@"八点钟学院 %d", b);
        };
        b= 100;
        instanceBlock();
    }
    
    @end
    

    转化为C++代码,对比得到简化后的block的C++代码,如下:

    #include "SJBlockCPlus.hpp"
    
    // 全局变量
    int thisGlobalValue = 1000;
    // 全局静态变量
    static int thisStaticValue = 10000;
    
    struct block_impl {
        
        void *isa;
        int Flags;
        int Reserved;
        void *FuncPtr;
    };
    
    struct block_desc_0 {
        size_t reserved;
        size_t Block_size;
    } __block_desc_0 = {0, sizeof(struct block_desc_0)};
    
    
    struct block_impl_0 {
        
        struct block_impl impl;
        struct block_desc_0* Desc;
        
        /*这后面跟block的变量参数:
         int i;  // 普通变量
         UILabel *label; // 局部对象
         self // 如果是成员变量,需要传self,因为成员变量要通过self进行访问。比如 self->label
         */
        
        int *i;  // 这么只能放在结构体block_impl后面,不然会越界,内存顺序中加了一个i,访问不到block_impl
        
        // 构造函数 i(_i) 这是赋值i=_i的意思
        block_impl_0(void *fp, struct block_desc_0 *desc, int *_i, int flags=0):i(_i) {
            
            impl.Flags = flags;
            impl.FuncPtr = fp;
            Desc = desc;
        }
    };
    
    
    static void block_func_0(struct block_impl_0 *__cself) {
        
    //    __cself->i = 100;
        //    printf("good My Love Ms Zhou == %d \n", __cself->i);
    
        // 传的地址所以修改要加*,打印也要加*转换
        *(__cself->i) = 100;
        printf("good My Love Ms Zhou == %d \n", *(__cself->i));
    
        
        // 因为作用域是全局的,所以全局变量和全局静态变量,可以直接访问
    //    printf("good My Love Ms Zhou == %d \n", thisGlobalValue);
    //    printf("good My Love Ms Zhou == %d \n", thisStaticValue);
    
    }
    
    void test() {
        
        // 局部静态变量传地址过去(因为地址是存在的,只是作用域和全局变量不一样)
        static int tmpStaticValue = 100000;
        struct block_impl_0 implTest = block_impl_0((void *)block_func_0, &__block_desc_0, &tmpStaticValue);
    
    //    int i = 10;
    //    struct block_impl_0 implTest = block_impl_0((void *)block_func_0, &__block_desc_0, i);
        void (*impTestPointer)() = (void (*)())&implTest;
        block_impl *tmpPointer = (block_impl *)impTestPointer;
        void (*Func)(block_impl *) = (void (*)(block_impl *))tmpPointer->FuncPtr;
        Func(tmpPointer);
        
    //    printf("i = %d\n", i);
        
    }
    

    由上可知,block主要是由两个结构体(block_impl和block_impl_0)和一个执行函数(block_func_0)构成。一些需要传的变量加在结构体block_impl_0中。
    总的结论:block你可以假想为一个class:变量(外部变量:成员变量,抓取的就是self,非成员变量抓取的就是这个非成员变量)、方法(执行函数)

    注意点
    修改的时候,要让存在栈区的变量和堆区的变量保持一致,所以在内部传的是地址过去,如下:

    - (void)blockDataBlockFunction {
        
        //要让栈区和堆区保持一致,所以修改的时候是传的地址过去,block实现中,实际上是将a转化为了一个结构体
        
        __block int a = 100;  //a在栈里
        
        void (^blockDataBlock)(void) = ^{
            
            // block会将a存放在堆区(栈区的a指向堆区的a,堆区的a指向自己,所以实际上是同一个a)
            a = 1000; //在堆区修改a的值
            NSLog(@"八点钟学院, %d", a);
            
        };  //blockDataBlock 在堆区
        
        a = 10; //在栈区修改a的值
        blockDataBlock();
        NSLog(@"栈区a = %d", a);
    }
    
    image.png

    两个的打印都是1000,栈区的a也因为block中的a(堆区)修改而改变了。

    相关文章

      网友评论

          本文标题:Block结构分析

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