与 Swift 中的 C 类交互

新手上路,请多包涵

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

还有其他问题在问,“我如何从 Swift 调用 C++ 函数。”这 不是 我的问题。要桥接到 C++ 函数,以下工作正常:

通过“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 代码现在可以直接调用函数

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

我的问题更具体。如何在 Swift 中实例化和操作 _C++ 类_?我似乎找不到任何关于此发表的内容。

原文由 David Hoelzer 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 799
2 个回答

我已经制定了一个完全可以管理的答案。你希望它有多干净完全取决于你愿意做多少工作。

首先,获取您的 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!

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

让它更清洁

虽然这是一个美妙的开始,并证明使用现有的 C++ 类和一个简单的桥是完全可行的,但它可以更加简洁。

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

完成此操作后,所有的桥接代码都完全封装在 Swift 类中。尽管我们仍在使用 C 桥接器,但我们有效地透明地使用了 C++ 对象,而无需求助于在 Objective-C 或 Objective-C++ 中重新编码它们。

原文由 David Hoelzer 发布,翻译遵循 CC BY-SA 3.0 许可协议

您可以使用 Scapix Language Bridge 自动将 C++ 桥接到 Swift(以及其他语言)。桥接代码直接从 C++ 头文件即时自动生成。这是一个 例子

C++:

 #include <scapix/bridge/object.h>

class contact : public scapix::bridge::object<contact>
{
public:
    std::string name();
    void send_message(const std::string& msg, std::shared_ptr<contact> from);
    void add_tags(const std::vector<std::string>& tags);
    void add_friends(std::vector<std::shared_ptr<contact>> friends);
};

迅速:

 class ViewController: UIViewController {
    func send(friend: Contact) {
        let c = Contact()

        contact.sendMessage("Hello", friend)
        contact.addTags(["a","b","c"])
        contact.addFriends([friend])
    }
}

原文由 Boris Rasin 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题
logo
Stack Overflow 翻译
子站问答
访问
宣传栏