如何在Swift中暴露含纯虚方法的C++监听器类并实现约束?
实现C++纯虚监听器向Swift的暴露与回调转发
当然有可行方案!核心思路是通过Objective-C++适配器模式,把Swift实现的逻辑桥接到C++的纯虚类上。下面是分步实现的详细方案,配合代码示例:
1. 定义Objective-C协议对应C++监听器
首先创建一个Objective-C协议,映射C++ ResultListener的纯虚方法,这样Swift可以通过遵守该协议来实现回调逻辑:
// TestResultListenerProtocol.h #import <Foundation/Foundation.h> @protocol TestResultListenerProtocol <NSObject> - (void)listenResult:(NSInteger)result; @end
2. 编写Objective-C++适配器类
这个适配器类是关键:它继承C的test::ResultListener,同时持有一个遵守上述Objective-C协议的对象,负责把C侧的回调转发给Swift实现的逻辑。注意文件后缀必须是.mm(表示Objective-C++文件):
头文件
// ResultListenerAdapter.h #import "TestResultListenerProtocol.h" #include "ResultListener.h" @interface ResultListenerAdapter : NSObject - (instancetype)initWithListener:(id<TestResultListenerProtocol>)listener; - (test::ResultListener*)cppListener; @end
实现文件
// ResultListenerAdapter.mm #import "ResultListenerAdapter.h" // 继承C++纯虚类的适配器实现 class CppResultListenerAdapter : public test::ResultListener { public: CppResultListenerAdapter(id<TestResultListenerProtocol> listener) : _listener(listener) {} // 重写纯虚方法,转发给Objective-C/Swift对象 void listenResult(int result) override { [_listener listenResult:(NSInteger)result]; } private: __weak id<TestResultListenerProtocol> _listener; // 用weak避免循环引用 }; @implementation ResultListenerAdapter { CppResultListenerAdapter* _cppAdapter; } - (instancetype)initWithListener:(id<TestResultListenerProtocol>)listener { self = [super init]; if (self) { _cppAdapter = new CppResultListenerAdapter(listener); } return self; } - (test::ResultListener*)cppListener { return _cppAdapter; } // 释放C++对象 - (void)dealloc { delete _cppAdapter; } @end
3. 包装C++的FunctionExecutor类
同样用Objective-C编写FunctionExecutor的包装类,暴露给Swift调用,内部负责把Swift传入的协议对象转换成C适配器:
头文件
// TestFunctionExecutor.h #import <Foundation/Foundation.h> #import "TestResultListenerProtocol.h" @interface TestFunctionExecutor : NSObject - (void)setListener:(id<TestResultListenerProtocol>)listener; @end
实现文件
// TestFunctionExecutor.mm #import "TestFunctionExecutor.h" #include "FunctionExecutor.h" #import "ResultListenerAdapter.h" @implementation TestFunctionExecutor { test::FunctionExecutor* _cppExecutor; ResultListenerAdapter* _listenerAdapter; } - (instancetype)init { self = [super init]; if (self) { _cppExecutor = new test::FunctionExecutor(); } return self; } - (void)setListener:(id<TestResultListenerProtocol>)listener { // 创建适配器并传给C++对象 _listenerAdapter = [[ResultListenerAdapter alloc] initWithListener:listener]; _cppExecutor->setListener(_listenerAdapter.cppListener); } - (void)dealloc { delete _cppExecutor; } @end
4. 配置桥接文件
在项目的Swift桥接文件(通常命名为[项目名]-Bridging-Header.h)中导入Objective-C头文件,让Swift可以访问这些类和协议:
#import "TestResultListenerProtocol.h" #import "TestFunctionExecutor.h"
5. Swift侧实现与调用
现在Swift可以直接遵守协议实现监听器,并传给包装后的TestFunctionExecutor:
// 实现监听器 class MyResultHandler: NSObject, TestResultListenerProtocol { func listenResult(_ result: Int) { print("Swift收到C++回调结果:\(result)") // 这里可以处理UI或业务逻辑 } } // 使用示例 let executor = TestFunctionExecutor() let handler = MyResultHandler() executor.setListener(handler)
注意事项
- 内存管理:适配器中使用
__weak修饰Objective-C对象,避免C++对象和Swift对象之间的循环引用。 - 线程安全:如果C++库在非主线程调用监听器,Swift中若涉及UI操作,需要手动切换到主线程(比如用
DispatchQueue.main.async)。 - 文件后缀:所有包含C++代码的Objective-C文件必须使用
.mm后缀,否则编译器会报错。
内容的提问来源于stack exchange,提问作者Marcos Lopez
相关产品推荐
相关产品推荐

