我有一个大量的用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 ++类 ?我似乎找不到任何发布的内容。
我已经找到了一个完全可管理的答案。您希望做到的清洁程度完全取决于您愿意完成的工作量。
首先,使用您的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 ++类和一个琐碎的桥梁是完全可行的,但它甚至可以变得更加干净。
清除这些内容仅意味着我们UnsafeMutablePointer<Void>从Swift代码的中间删除了,并将其封装到Swift类中。本质上,我们使用相同的C / C 包装函数,但将它们与Swift类接口。Swift类维护对象引用,实际上只是通过桥将所有方法和属性引用调用传递给C 对象!
UnsafeMutablePointer<Void>
完成此操作后,所有桥接代码都完全封装在Swift类中。即使我们仍在使用C桥,我们也有效地透明地使用C 对象,而不必诉诸于Objective- C或Objective-C 。