iOS OC 项目集成 C++ 算法库完整指南
一、概述思路与实现方式
1.1 核心思路
在 iOS 原生 Objective-C 项目中集成 C++ 算法库,核心思路和 Android 的 JNI 类似,但实现方式更轻量 。我们不需要像 Android 那样通过 JNI 接口层和 javac/javah 工具生成头文件,而是直接利用 Xcode 对 Objective-C++ 的原生支持。
本质就是:给 C++ 代码套上一层 Objective-C 的"壳",让 OC 业务层完全感知不到 C++ 的存在。
术语:
"在 iOS 中,我们通过 Objective-C++ 编写一个 Wrapper 层,来封装 C++ 算法库,为上层提供 OC 接口。"
- 最标准的说法是 "Objective-C++",这是 Apple 官方术语。
- 最常用的开发语境是 "OC++ Wrapper",清晰明了。
- "Bridge/桥接层" 是口语化的概念描述,不是标准术语,但大家能听懂。
- 绝对不要叫 "iOS JNI",这是外行说法。
1.2 三层架构
┌─────────────────────────────────────────┐
│ 第 1 层:OC 业务层 │
│ (ViewController.m) │
│ 只写 OC 代码,不涉及任何 C++ │
└─────────────────┬───────────────────────┘
│ 调用 OC 接口
┌─────────────────▼───────────────────────┐
│ 第 2 层:OC 桥接层 (关键) │
│ (Bridge.mm) │
│ Objective-C++ 混编文件 │
│ 翻译:OC 方法 → C++ 方法调用 │
└─────────────────┬───────────────────────┘
│ 持有 C++ 对象
┌─────────────────▼───────────────────────┐
│ 第 3 层:C++ 算法层 │
│ (Algorithm.cpp) │
│ 纯 C++ 实现,跨平台可复用 │
└─────────────────────────────────────────┘
1.3 关键技术点
| 技术点 | 说明 |
|---|---|
.mm 文件 |
Objective-C++ 源文件,同时支持 OC 和 C++ 语法 |
| C++ 对象管理 | C++ 对象需要手动 new/delete,ARC 不负责 |
| 类型转换 | NSString → std::string,NSInteger → int 等 |
| 头文件隔离 | 桥接类的 .h 不能包含任何 C++ 代码,避免污染纯 OC 文件 |
1.4 与 JNI 的对比
| 对比项 | Android JNI | iOS OC++ |
|---|---|---|
| 桥接语言 | C/C++ | Objective-C++ |
| 桥接文件 | .c/.cpp + javah 生成头文件 |
.mm 直接编写 |
| 对象管理 | JNI 局部/全局引用 | C++ 手动 new/delete + ARC |
| 类型映射 | jstring ↔ char* |
NSString* ↔ std::string |
| 回调实现 | JNI 回调 Java 方法 | 函数指针/std::function + dispatch_async |
二、项目整体结构
2.1 目录结构
MyApp/
├── MyApp.xcodeproj/
│
├── MyApp/ # 主工程目录
│ │
│ ├── AppDelegate.h/m # OC - 应用代理
│ │
│ ├── ViewControllers/ # 📂 OC 业务层
│ │ ├── MainViewController.h
│ │ └── MainViewController.m
│ │
│ ├── Bridge/ # 📂 🔑 桥接层(重点)
│ │ ├── CalculatorBridge.h # OC 接口声明(纯 OC)
│ │ └── CalculatorBridge.mm # OC++ 实现(混编)
│ │
│ ├── CPP/ # 📂 C++ 算法核心
│ │ ├── Algorithms/
│ │ │ ├── Calculator.hpp # C++ 类声明
│ │ │ └── Calculator.cpp # C++ 类实现
│ │ └── ThirdParty/ # 第三方 C++ 库
│ │ ├── include/
│ │ └── lib/
│ │
│ ├── Models/ # 📂 OC 数据模型
│ ├── Resources/ # 📂 资源文件
│ └── main.m # OC 程序入口
│
└── Tests/ # 单元测试
2.2 文件类型速查表
| 文件后缀 | 存放位置 | 编译方式 | 职责 |
|---|---|---|---|
.h |
各处 | 不单独编译 | 接口声明(OC 或 C++) |
.m |
ViewControllers/, Models/ | Objective-C | UI、业务逻辑 |
.mm |
Bridge/ | Objective-C++ | OC ↔ C++ 翻译桥接 |
.hpp |
CPP/ | 不单独编译 | C++ 类/函数声明 |
.cpp |
CPP/ | C++ | 核心算法实现 |
2.3 依赖关系图
MainViewController.m
│ #import "CalculatorBridge.h"
▼
CalculatorBridge.h (纯 OC 接口)
│
▼
CalculatorBridge.mm (OC++ 实现)
│ #import "Calculator.hpp"
│ 持有 C++ 对象指针
▼
Calculator.hpp + Calculator.cpp (纯 C++)
三、关键示例代码
3.1 C++ 算法层:累加器
Calculator.hpp(头文件 - 声明)
cpp
#pragma once
class Calculator {
public:
Calculator(); // 构造函数
~Calculator(); // 析构函数
int add(int value); // 累加并返回结果
void reset(); // 重置为 0
int getCurrent() const; // 获取当前值
private:
int _sum;
};
Calculator.cpp(源文件 - 实现)
cpp
#include "Calculator.hpp"
Calculator::Calculator() : _sum(0) {}
Calculator::~Calculator() {}
int Calculator::add(int value) {
_sum += value;
return _sum;
}
void Calculator::reset() {
_sum = 0;
}
int Calculator::getCurrent() const {
return _sum;
}
3.2 OC 桥接层(核心)
CalculatorBridge.h(纯 OC 接口 - 暴露给业务层)
objectivec
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
/// 计算器桥接类 - OC 调用入口
@interface CalculatorBridge : NSObject
/// 初始化计算器
- (instancetype)init;
/// 累加数值并返回当前总和
- (NSInteger)addNumber:(NSInteger)number;
/// 重置计算器
- (void)reset;
/// 获取当前总和
- (NSInteger)currentSum;
@end
NS_ASSUME_NONNULL_END
CalculatorBridge.mm(OC++ 实现 - 桥接核心)
objectivec
#import "CalculatorBridge.h"
#import "Calculator.hpp" // ⭐ 引入 C++ 头文件
// 类扩展 - 存放 C++ 对象指针
@interface CalculatorBridge () {
Calculator *_cppCalculator; // ⭐ 持有 C++ 对象指针
}
@end
@implementation CalculatorBridge
- (instancetype)init {
self = [super init];
if (self) {
// ⭐ 手动创建 C++ 对象
_cppCalculator = new Calculator();
NSLog(@"✅ 计算器已初始化");
}
return self;
}
// ⭐ 核心:OC 方法 → C++ 方法调用
- (NSInteger)addNumber:(NSInteger)number {
if (!_cppCalculator) return 0;
int result = _cppCalculator->add((int)number);
return (NSInteger)result;
}
- (void)reset {
if (_cppCalculator) {
_cppCalculator->reset();
}
}
- (NSInteger)currentSum {
if (!_cppCalculator) return 0;
return (NSInteger)_cppCalculator->getCurrent();
}
// ⭐ 关键:手动释放 C++ 对象
- (void)dealloc {
if (_cppCalculator) {
delete _cppCalculator; // ⭐ ARC 不会自动释放 C++ 对象
_cppCalculator = nullptr;
NSLog(@"🗑️ C++ 对象已释放");
}
}
@end
3.3 OC 业务层:使用桥接
MainViewController.m(业务代码,纯 OC)
objectivec
#import "MainViewController.h"
#import "CalculatorBridge.h" // ⭐ 只引入 OC 桥接头文件
@interface MainViewController ()
@property (nonatomic, strong) CalculatorBridge *calculator;
@property (weak, nonatomic) IBOutlet UILabel *resultLabel;
@end
@implementation MainViewController
- (void)viewDidLoad {
[super viewDidLoad];
// ⭐ 完全 OC 风格,感知不到 C++ 的存在
self.calculator = [[CalculatorBridge alloc] init];
// 累加测试
[self.calculator addNumber:10]; // → 10
[self.calculator addNumber:20]; // → 30
[self.calculator addNumber:5]; // → 35
NSInteger sum = [self.calculator currentSum];
self.resultLabel.text = [NSString stringWithFormat:@"总和: %ld", (long)sum];
// 输出: 总和: 35
}
- (IBAction)onAddButtonClick:(id)sender {
NSInteger random = arc4random_uniform(100);
NSInteger result = [self.calculator addNumber:random];
NSLog(@"➕ 加 %ld,当前总和: %ld", (long)random, (long)result);
}
- (IBAction)onResetButtonClick:(id)sender {
[self.calculator reset];
self.resultLabel.text = @"已重置";
}
@end
3.4 进阶:带 C++ 回调的桥接
当 C++ 算法需要通知 OC 层(如进度回调)时:
Calculator.hpp(增加回调支持)
cpp
#pragma once
#include <functional>
class Calculator {
public:
// 回调类型定义
using ProgressCallback = std::function<void(int percent)>;
Calculator();
~Calculator();
void setProgressCallback(ProgressCallback callback);
void longRunningTask(); // 耗时任务,会触发回调
private:
ProgressCallback _callback;
};
CalculatorBridge.mm(处理回调)
objectivec
#import "CalculatorBridge.h"
#import "Calculator.hpp"
@interface CalculatorBridge () {
Calculator *_cppCalculator;
}
@end
@implementation CalculatorBridge
- (void)startLongTask {
__weak typeof(self) weakSelf = self;
// 设置 C++ 回调
_cppCalculator->setProgressCallback([weakSelf](int percent) {
// ⭐ 回到主线程更新 UI
dispatch_async(dispatch_get_main_queue(), ^{
[weakSelf updateProgress:percent];
});
});
// 启动耗时任务(在子线程执行)
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
_cppCalculator->longRunningTask();
});
}
- (void)updateProgress:(int)percent {
self.progressView.progress = percent / 100.0;
self.progressLabel.text = [NSString stringWithFormat:@"%d%%", percent];
}
@end
3.5 类型转换速查表
| OC 类型 | C++ 类型 | 转换方式 |
|---|---|---|
NSInteger |
int |
(int)value |
NSString* |
std::string |
std::string([str UTF8String]) |
std::string |
NSString* |
[NSString stringWithUTF8String:str.c_str()] |
NSArray<T*>* |
std::vector<T> |
遍历 [array enumerateObjectsUsingBlock:] |
NSData* |
const char* |
(const char*)[data bytes] |
转换示例:
objectivec
// OC → C++
NSString *name = @"John";
std::string cppName = std::string([name UTF8String]);
// C++ → OC
std::string cppResult = "Hello";
NSString *ocResult = [NSString stringWithUTF8String:cppResult.c_str()];
四、关键注意事项
| 序号 | 注意点 | 说明 |
|---|---|---|
| 1 | 文件后缀 | 桥接文件必须用 .mm,不能用 .m |
| 2 | 头文件隔离 | 桥接类的 .h 不能引入 C++ 头文件 |
| 3 | 内存管理 | C++ 对象必须手动 new/delete |
| 4 | 类型转换 | 注意 OC 与 C++ 类型的相互转换 |
| 5 | 线程安全 | C++ 回调若涉及 UI,需切回主线程 |
| 6 | 编译设置 | Xcode 默认支持,无需额外配置 |
五、总结
┌────────────────────────────────────────────────────────────┐
│ 集成流程一图流 │
├────────────────────────────────────────────────────────────┤
│ │
│ 1. 写 C++ 算法 → Calculator.hpp + Calculator.cpp │
│ ↓ │
│ 2. 写 OC 桥接类 → CalculatorBridge.h (纯 OC 接口) │
│ ↓ │
│ 3. 实现桥接 .mm → CalculatorBridge.mm │
│ - #import "Calculator.hpp" │
│ - 持有 C++ 对象指针 `_cppCalculator` │
│ - OC 方法里调用 `_cppCalculator->方法()` │
│ - dealloc 里 `delete _cppCalculator` │
│ ↓ │
│ 4. 业务层调用 → 只 #import "CalculatorBridge.h" │
│ ↓ │
│ 5. 编译运行 → Xcode 自动处理 .cpp + .mm │
│ │
└────────────────────────────────────────────────────────────┘
核心要诀: .mm 是唯一的跨语言接触点,负责"翻译"和"生命周期管理",OC 业务层完全透明。这就是 iOS 上的 JNI!