我有一个重要的类库,用C++编写.我试图通过Swift中的某种桥梁来使用它们,而不是将它们重写为Swift代码.主要的动机是C++代码代表了在多个平台上使用的核心库.实际上,我只是创建了一个基于Swift的UI,以允许核心功能在OS X下工作.

还有其他问题要问,"我如何调用SWIFT的C++函数."这是我的问题.为了桥接到C++函数,下面的工作很好:

Define a bridging header through "C"

#ifndef ImageReader_hpp
#define ImageReader_hpp

#ifdef __cplusplus
extern "C" {
#endif

    const char *hexdump(char *filename);
    const char *imageType(char *filename);

#ifdef __cplusplus
}
#endif

#endif /* ImageReader_hpp */

Swift code can now call functions directly

let type = String.fromCString(imageType(filename))
let dump = String.fromCString(hexdump(filename))

我的问题更具体.我如何从Swift中实例化和操作C++ Class?我似乎找不到任何关于这个的文章.

推荐答案

我已经想出了一个完全可行的答案.你希望这件事有多干净完全取决于你愿意做多少工作.

首先,使用C++类并创建C"包装器"函数与之接口.例如,如果我们有这个C++类:

class MBR {
    std::string filename;

public:
    MBR (std::string filename);
    const char *hexdump();
    const char *imageType();
    const char *bootCode();
    const char *partitions();
private:
    bool readFile(unsigned char *buffer, const unsigned int length);
};

然后我们实现这些C++函数:

#include "MBR.hpp"

using namespace std;
const void * initialize(char *filename)
{
    MBR *mbr = new MBR(filename);

    return (void *)mbr;
}

const char *hexdump(const void *object)
{
    MBR *mbr;
    static char retval[2048];

    mbr = (MBR *)object;
    strcpy(retval, mbr -> hexdump());
    return retval;
}

const char *imageType(const void *object)
{
    MBR *mbr;
    static char retval[256];

    mbr = (MBR *)object;
    strcpy(retval, mbr -> imageType());
    return retval;
}

然后,桥头包含:

#ifndef ImageReader_hpp
#define ImageReader_hpp

#ifdef __cplusplus
extern "C" {
#endif

    const void *initialize(char *filename);
    const char *hexdump(const void *object);
    const char *imageType(const void *object);

#ifdef __cplusplus
}
#endif

#endif /* ImageReader_hpp */

通过Swift,我们现在可以实例化对象并与之交互,如下所示:

let cppObject = UnsafeMutablePointer<Void>(initialize(filename))
let type = String.fromCString(imageType(cppObject))
let dump = String.fromCString(hexdump(cppObject))                
self.imageTypeLabel.stringValue = type!
self.dumpDisplay.stringValue = dump!

因此,正如您所见,解决方案(实际上相当简单)是创建包装器,将实例化一个对象并返回指向该对象的指针.然后可以将其传递回包装器函数,包装器函数可以轻松地将其视为符合该类的对象,并调用成员函数.

Making It Cleaner

虽然这是一个奇妙的开始,并证明使用一个普通的桥来使用现有的C++类是完全可行的,但它甚至可以更干净.

清理这一点只意味着我们从Swift代码的中间删除UnsafeMutablePointer<Void>,并将其封装到Swift类中.本质上,我们使用相同的C/C++包装函数,但将它们与Swift类接口.Swift类维护对象引用,基本上只是通过桥将所有方法和属性引用调用传递给C++对象!

完成这项工作后,所有桥接代码都完全封装在Swift类中.即使我们仍在使用C桥,我们仍然有效地使用C++对象,而不必在Objtovi-C或Objul-C++中重新编码它们.

Swift相关问答推荐

启用完成并发判断以及如何解决警告(续)

在运行时检测蒸汽工人的类型

如何在SWIFT中解码Instagram Backup中的字符串?

如何获取SCNCamera正在查看的网格点(SCNNode)的局部坐标和局部法线?

如何将图像插入到矩形中

为什么ClosedRange<;Int&>包含的速度比预期慢340万倍?

仅使用@MainActor注释类的部分时的并发问题

在 init(from decoder: Decoder) 方法中访问原始 JSON 数据

如何在 swiftui 中设置给定字符串类型日期的日期倒计时?

如何将变量添加到不属于可解码部分的 struct ?

从文字创建数组时的 Swift 宏

RxSwift 中 Single.just(...) 和 Observable.just(...) 之间有区别吗?

将内容与工作表顶部而不是中间对齐

Swift - 获取本地日期和时间

'NSLog' 不可用:可变参数函数在 swift 中不可用

为 UIActivityViewController Swift 设置不同的活动项

UITableViewCell 不显示 detailTextLabel.text - Swift

Swift - 迭代 struct 对象时如何对其进行变异

判断用户是否登录到 iCloud?Swift /iOS

Swift 中的 recursiveDescription 方法?