我已经想出了一个完全可行的答案.你希望这件事有多干净完全取决于你愿意做多少工作.
首先,使用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++中重新编码它们.