前言

最近在研究 Cronet 网络库,涉及到 AndroidiOS ,由于对 OC 不怎么熟悉,所以在使用的时候碰到了 C++OC 互相调用的问题,于是便有了此文。

字符串转换

1
2
3
4
5
6
// NSString -> std::string
NSString* str = @"oc string";
std::string s = std::string([str UTF8String]);

// std::string -> NSString
NSString* nstr = [NSString stringWithCString: str.c_str() encoding: [NSString defaultCStringEncoding]];

C++ 调用 OC Block

由于 .cpp 文件无法识别 OC 的代码, .m 文件无法识别 C++ 的代码,所以这两者之间相互调用需要写在 .mm 的文件中,这样编译器才能识别。

C++ 的代码要写在 .mm 文件中,因为在 .hOC 无法识别 class 关键字

来看一个例子,先定义一个头文件 InvokeBlock.h

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
#import <Foundation/Foundation.h>

// 定义一个OC Block
typedef void(^OCBlock)();

@interface Ocpp : NSObject

// 申明一个 OC 的初始化方法,用于传递 Block
+ (void) InitBlock: (OCBlock)block;

@end

导入 OC 的头文件要使用 #importC++ 的可以使用 #include

这里要注意 C++ 和 OC 混编一定要 .mm 的后缀,这样才能被识别。

定义 InvokeBlock.mm

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#import "InvokeBlock.h"

class InvokeBlock {

public:
    InvokeBlock(OCBlock block) : block_(block) {}

    // 调用 Block
    void invoke() {
        block_();
    }

private:
    // 保存Block
    __strong OCBlock block_;
};

@implementation Ocpp

// 定义 InitBlock,创建 InvokeBlock,并把block 传进去
+ (void)InitBlock: (OCBlock)block{
    InvokeBlock* invokeBlock = new InvokeBlock(block);
    invokeBlock->invoke(); // 调用invoke用于回调block
    delete invokeBlock; // 用完释放
}

@end

C++ 的代码要写在 .mm 中,不能写在头文件中,不然会报错。估计是识别不了。

接着就可以在 ViewController.m 中使用了

1
2
3
4
5
6
- (void)viewDidLoad {
    [super viewDidLoad];
    [Ocpp InitBlock:^{
        NSLog(@"block invoke from c++");
    }];
}

执行之后控制台就打印了 block invok from c++

参考