ObjectiveC混编 c++

1、C++的特点

1.1 C++ 跨平台性

  c++是编译出来的二进制文件在Android、IOS、甚至在WP上都可以正常运行。还有很多其他的跨平台语言,比如之前曾经流行过的H5、ReactNative,还有现下最是火热的 Flutter,他们都属于解释型跨平台,约定好一种脚本语言,底层辅助以各平台的基础实现。比如ReactNative的开发中使用JavaScriptCore,单本质上还是在运行时解释js然后再执行native,真正参与编译的是 语法解释器+NA底层代码而不是js,他们或多或少都是通过c++实现的。

1.2 ObjectiveC 与 C++ 向下兼容C

ObjectiveC 与 C++ 都向下兼容C ,是他们的共同点和纽带。

  OC中的对象虽然有ARC辅助内存管理,但本质上还是一个void *,同理C++也一样是void *,OC之所以调用函数叫做发送消息(sendMsg),是因为封装了层独有的runtime机制(这机制还是C的),但归根结底每个函数实体依然是一个IMP,依然是一个函数指针,这一点和C++也一样,所以他们之间的衔接才会如此通畅。

2、ObjectiveC 与 C++ 混编

混编过程中主要存在以下三种文件:
  • 纯C++类:只需要分别创建对应的 .h 和 .cpp 文件,直接导入工程并配置到对应TARGETS 的Compile Sources 下 即可。如果需要使用C++标准库,还需要导入libc++库。即创建下图2中的2 和 3。如下图所示:


图1:配置示例.png

• 混编文件 .mm 文件:如果你想创建一个能即识别C++又识别OC的对象,只需要照常创建一个.h 文件和.m文件,然后将.m文件重命名成.mm文件,就是告诉编译器,这个文件可以进行混编 — ObjectiveC++。即创建下图中的1,然后修改文件名后缀。
  • 纯OC类: .m文件和对应的头文件,即创建下图中的1。


图2: 文件类型示例.png

3、OC&C++混编示例

  如果想要在c++ 文件中直接使用 OC对象,则需要 此 c++ 文件后缀改为.mm, 然后在此文件中使用OC 对象,不要在对应的.h 文件中使用,.h 文件中还是 c++的数据结构。这里1以 OC环境下调用C++代码为例进行说明。

1)创建纯 c++类文件 CppFile.h 和 CppFile.cpp,其中 .h 文件如下所示

#pragma once

#include <string>
//using std::string;


class CppFile {
public:
    CppFile(const std::string name);
    ~CppFile();
public:
    void DoSomething(const std::string& str);
};

2)创建 混编文件 OCCFile.h 和 OCCFile.m, 然后将OCCFile.m 文件后缀修改为 .mm, 其中 头文件如下所示:

#pragma once

#import <Foundation/Foundation.h>
#include "CppFile.h"

@interface OCCFile : NSObject
{
    CppFile* mCppFile;
}

- (void)doSomethingWithString:(NSString*)str;

@end

3)在demo工程的ViewController.m 文件中引用我们创建混编文件 OCCFile.h

#import "ViewController.h"
#import "OCCFile.h"

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    OCCFile* occFile = [OCCFile new];
    [occFile doSomethingWithString:@"How do you do!"];
}


@end

此时编译以下,我们要养成好习惯边写边编译,这样子可以最快的发现问题,我们看看现在会有什么问题 🤔!
出错了🤔!是的,你没有看错,build 失败了,说好的C++和OC 完美结合呢?

Build.png

C++和OC是完美结合的,我们说的是.m 文件修改为 .mm 文件之后,能够让xcode编译器知道这是一个混编文件,因为xcoce 可以识别.mm 的混编语法。但是xcode不识别 .h文件中的混编语法,也不识别.hh 语法为混编。也就是对于xcode 来说:
  • 如果.h 文件中都是 C++ 接口(比如CppFile.h) , 或者都为 OC (比如 ViewController.h 文件)都是没有问题;
  • 如果.h 文件是混编的,当然 引入 纯c++的头文件也是不可以,死心眼的 xcode 就是认识 。

那怎么处理呢?有下面两个办法:
  • 将文件或者方法移到xcode 编译器识别的混编的 .mm 文件里;

#pragma once
-------CppFile.h
#import <Foundation/Foundation.h>
//#include "CppFile.h"

@interface OCCFile : NSObject
{
//  CppFile* mCppFile; 
}

- (void)doSomethingWithString:(NSString*)str;

@end

-------CppFile.cpp
#import "OCCFile.h"
#include "CppFile.h"//移动到这里了了...

@interface OCCFile ()
{
    CppFile* mCppFile;//移动到这里了了...
}

@end

@implementation OCCFile

- (id)init
{
    if (self == [super init])
    {
        printf("=======My name is OCCFile.\n ");
    }
    return self;
}

- (void)doSomethingWithString:(NSString*)str
{

}

@end

• 使用 通过 OC对象id 和 c语言的 void * 😅,然后在 .mm 中进行类型转换;

#pragma once

#import <Foundation/Foundation.h>
//#include "CppFile.h"

@interface OCCFile : NSObject
{
//  CppFile* mCppFile;
    id mCppFile;//可以修改成这样子,😄
}

- (void)doSomethingWithString:(NSString*)str;

@end


void* 是指针的最原本形态,利用它我们随意的进行C++和OC的混编,但是因为OC 对象 存在内存管理,但是 C++ 是没有的,所以在ARC下需要进行下特殊处理。
  • __bridge: ARC下OC对象和Core Foundation对象之间的桥梁,转化时只涉及对象类型不涉及对象所有权的转化;
  • __bridge_retained: 将内存所有权同时归原对象和变换后的对象持有,并对变换后的对象做一次reatain
  • __bridge_transfer:将内存所有权彻底移交变换后的对象持有,retain变换后的对象,release变换前的对象

思路:
  首先,在全局区域声明了一个全局的函数指针 OCInterfaceCFunction,用来处理所有跨C++回调OC事件。

#pragma once
typedef void(*OCInterfaceCFunction)(void*, void*);

  然后,在创建纯OC类(OCInterfaceCC.m)文件中也实现了这一个函数指针MyObjectDoSomethingWith,这个OCInterfaceCFunction实体就是我们的接口通道了。

----- 纯OC类
#import "OCInterfaceC.h"
#include "OCInterfaceCFile.h"

void MyObjectDoSomethingWith(void* obj, void* param)
{
    [(__bridge id)obj dosomthing:param];
}


@implementation OCInterfaceC

- (id)init
{
    self = [super init];
    
    if (self)
    {
        _call = MyObjectDoSomethingWith;
    }
    
    return self;
}


- (int)dosomthing:(void *)param
{
    printf("hei, there is OC .....\n");
    
    return 0;
}
@end

------ 纯c++类
#include "InterfaceCC.h"
#include <stdio.h>


InterfaceCC::InterfaceCC(void* ocObj, OCInterfaceCFunction interfaceFunction)
{
    mOCObj = ocObj;
    mInterfaceFunction = interfaceFunction;
}

InterfaceCC::~InterfaceCC()
{
    
}

void InterfaceCC::doSomthings()
{
    printf("there is c++.\n");
    
    mInterfaceFunction(mOCObj,NULL);
}

  最后,当初始化纯c++类( InterfaceCC)的时候,将以创建好的OCInterfaceCC和这个OCInterfaceCFunction一并传入,当Cpp需要调用Oc的时候,直接使用OCInterfaceCC与OCInterfaceCFunction即可。

OCInterfaceC* OCtoC = [[OCInterfaceC alloc] init];
void* CCPointer = (__bridge void*)OCtoC;
InterfaceCC* cc = new InterfaceCC(CCPointer, OCtoC.call);
cc->doSomthings();

这样做的好处是可以隔离两种语言避免开发上的混乱和困难。比如C++做三方库在一个以OC为主的环境中进行使用,OC需要任意调用C++的各种接口和对象,但是不希望三方库直接引用oc头文件,希望三方库解耦,只通过固定回调或者协议来通信。示通过创建中间文件专门处理交互,可以降低模块间的耦合度, 否则 处理维护起来会非常困难;

完整Demo地址:https://github.com/starmier/OCFlutterCDemo

4、总结

.h 需要保持各自的数据结构,保证纯正的C++ 或 OC;

将需要混编引用的.m 或者 .cpp文件的后缀修改为 .mm ,告诉编译器 这个文件可以进行混编 --- ObjectiveC++;

Objective-C 和 C++ 都是向下兼容 C的,可以通过灵活的使用 void *指针 作为纽带在两者之间传递对象;

Objective-c 可以通过工程的Build Settings/Apple Clang - Language - Objective-C/ Objective-C Automatic Reference Counting 来配置模式内存管理为 ARC(特定文件配置标示:-objc-arc) 或则 MRC(特定文件配置标示:-fno-objc-arc),但是 C++ 的内存管理是谁创建谁释放的原则;故在一个项目如果要使用多种语言,尽量的将两种语言分开封装,各自内部维护内存;

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 151,688评论 1 330
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 64,559评论 1 273
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 101,749评论 0 226
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 42,581评论 0 191
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 50,741评论 3 271
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 39,684评论 1 192
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,122评论 2 292
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 29,847评论 0 182
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 33,441评论 0 228
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 29,939评论 2 232
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,333评论 1 242
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 27,783评论 2 236
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,275评论 3 220
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 25,830评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,444评论 0 180
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 34,553评论 2 249
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 34,618评论 2 249

推荐阅读更多精彩内容