将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(堆区)修改而改变了。













网友评论