You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ObjC++与Swift桥接中二维数组回调传递问题求解

我之前在做ObjC++和Swift桥接时也碰到过类似的复杂容器传递问题,给你几个亲测可行的解决方案,按需选择:

方案1:转成ObjC嵌套数组(最省心,适合大部分场景)

Swift能直接和NSArray无缝桥接,所以核心思路是在ObjC++端把vector<vector<string>>转换成NSArray<NSArray<NSString*>*>*,再通过代理传递,Swift端就能直接拿到[[String]]类型。

步骤1:ObjC++端做类型转换

// 假设你已有目标二维vector:cpp2DVector
NSMutableArray *objc2DArray = [NSMutableArray array];
for (const auto& row : cpp2DVector) {
    NSMutableArray *objcRow = [NSMutableArray array];
    for (const auto& str : row) {
        // 把C++ string转成NSString
        [objcRow addObject:@(str.c_str())];
    }
    [objc2DArray addObject:objcRow];
}
// 通过代理传递转换后的数组
[self.delegate myCallbackInstance:objc2DArray];

步骤2:调整代理协议和Swift方法

注意:代理协议必须放在纯ObjC头文件(.h)里,不能包含任何C++类型,否则Swift无法识别:

// MyDelegate.h
@protocol MyDelegate <NSObject>
- (void)myCallbackInstance:(NSArray<NSArray<NSString*>*>*)value;
@end

Swift端的代理方法直接适配类型即可:

func callback(_ myCallbackValue: [[String]]) {
    print(myCallbackValue)
}

方案2:直接传递指针(性能敏感场景用)

如果数据量极大,不想做内存拷贝,可以直接传递C++ vector的指针,但要严格管理内存生命周期,避免野指针崩溃。

ObjC++端传递指针和尺寸

const auto& cpp2DVector = yourTargetVector;
size_t rowCount = cpp2DVector.size();
// 把vector的指针和行数一起传给Swift
[self.delegate myCallbackWithRowCount:rowCount dataPtr:(void*)&cpp2DVector];

Swift端解析指针

func callbackWithRowCount(_ rowCount: Int, dataPtr: UnsafeMutableRawPointer) {
    // 将原始指针绑定到C++二维vector类型
    let cppVectorPtr = dataPtr.assumingMemoryBound(to: [[CChar]].self)
    let cpp2DVector = cppVectorPtr.pointee
    
    // 逐行解析成Swift数组
    var swift2DArray = [[String]]()
    for row in cpp2DVector {
        let swiftRow = row.map { String(cString: $0) }
        swift2DArray.append(swiftRow)
    }
    print(swift2DArray)
}

⚠️ 关键提醒:必须保证在Swift解析完成前,ObjC++端的cpp2DVector不会被释放或销毁,否则会触发崩溃。

方案3:自定义ObjC包装类(频繁传递场景用)

如果需要反复传递这种二维字符串数组,可以写一个ObjC包装类,内部持有C++ vector,对外提供安全的Swift访问接口。

步骤1:写包装类的头文件(纯ObjC)

// String2DArrayWrapper.h
@interface String2DArrayWrapper : NSObject
- (NSInteger)rowCount;
- (NSInteger)columnCountForRow:(NSInteger)row;
- (NSString*)stringAtRow:(NSInteger)row column:(NSInteger)column;
@end

步骤2:在ObjC实现文件里封装C逻辑

// String2DArrayWrapper.mm
#import "String2DArrayWrapper.h"
#include <vector>
#include <string>

@interface String2DArrayWrapper ()
@property (nonatomic, assign) std::vector<std::vector<std::string>>* internalVector;
@end

@implementation String2DArrayWrapper

- (instancetype)initWithCppVector:(std::vector<std::vector<std::string>>*)vector {
    self = [super init];
    if (self) {
        // 深拷贝C++ vector到内部,避免外部释放导致崩溃
        _internalVector = new std::vector<std::vector<std::string>>(*vector);
    }
    return self;
}

- (void)dealloc {
    // 释放内部持有的C++ vector
    delete _internalVector;
    [super dealloc];
}

- (NSInteger)rowCount {
    return _internalVector->size();
}

- (NSInteger)columnCountForRow:(NSInteger)row {
    if (row < 0 || row >= _internalVector->size()) return 0;
    return (*_internalVector)[row].size();
}

- (NSString*)stringAtRow:(NSInteger)row column:(NSInteger)column {
    if (row < 0 || row >= _internalVector->size()) return nil;
    auto& rowVec = (*_internalVector)[row];
    if (column < 0 || column >= rowVec.size()) return nil;
    return @(rowVec[column].c_str());
}

@end

步骤3:传递包装类并在Swift解析

ObjC++端:

std::vector<std::vector<std::string>> cpp2DVector = yourData;
String2DArrayWrapper *wrapper = [[String2DArrayWrapper alloc] initWithCppVector:&cpp2DVector];
[self.delegate myCallbackInstance:wrapper];

Swift端:

func callback(_ wrapper: String2DArrayWrapper) {
    var swift2DArray = [[String]]()
    let rowCount = wrapper.rowCount()
    for row in 0..<rowCount {
        let columnCount = wrapper.columnCount(forRow: row)
        var swiftRow = [String]()
        for column in 0..<columnCount {
            if let str = wrapper.string(atRow: row, column: column) {
                swiftRow.append(str)
            }
        }
        swift2DArray.append(swiftRow)
    }
    print(swift2DArray)
}

通用注意事项

  • 所有涉及C++类型的代码必须放在.mm文件里,不能暴露在.h头文件中,否则Swift无法识别
  • 代理协议必须是纯ObjC协议,不能包含任何C++相关类型
  • 数据量小选方案1,性能敏感选方案2,频繁传递选方案3

内容的提问来源于stack exchange,提问作者user9590073

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 03:57:27