У меня есть значительная библиотека классов, написанных на C ++. Я пытаюсь использовать их через какой-то тип моста в Swift, а не переписывать их как код Swift. Основная мотивация заключается в том, что код C ++ представляет собой базовую библиотеку, которая используется на нескольких платформах. По сути, я просто создаю пользовательский интерфейс на основе Swift, чтобы основные функции работали под OS X.
Есть и другие вопросы: «Как вызвать функцию C ++ из Swift». Это не мой вопрос. Для перехода к функции 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))
Мой вопрос более конкретный. Как я могу создать экземпляр класса C ++ и управлять им из Swift? Кажется, я не могу найти что-либо опубликованное по этому поводу.
Ответы:
Я придумал вполне управляемый ответ. Насколько чистым вы хотите, чтобы это было, полностью зависит от того, сколько работы вы готовы делать.
Во-первых, возьмите свой класс 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 ++!После этого весь код моста полностью инкапсулируется в класс Swift. Несмотря на то, что мы все еще используем мост C, мы эффективно используем объекты C ++ прозрачно, не прибегая к их перекодированию в Objective-C или Objective-C ++.
источник
В настоящее время Swift не поддерживает взаимодействие с C ++. Это долгосрочная цель, но вряд ли она произойдет в ближайшем будущем.
источник
Помимо вашего собственного решения, есть еще один способ сделать это. Вы можете вызвать или напрямую написать код C ++ в objective-c ++.
Таким образом, вы можете создать оболочку объектного C ++ поверх кода C ++ и создать подходящий интерфейс.
Затем вызовите код объектного C ++ из вашего быстрого кода. Чтобы иметь возможность писать объективный код C ++, вам может потребоваться переименовать расширение файла с .m на .mm.
Не забывайте освобождать память, выделенную вашими объектами C ++, когда это необходимо.
источник
Как упоминалось в другом ответе, использовать ObjC ++ для взаимодействия намного проще. Просто назовите свои файлы .mm вместо .m и xcode / clang, и вы получите доступ к C ++ в этом файле.
Обратите внимание, что ObjC ++ не поддерживает наследование C ++. Если вы хотите создать подкласс класса C ++ в ObjC ++, вы не можете. Вам нужно будет написать подкласс на C ++ и обернуть его вокруг класса ObjC ++.
Затем используйте заголовок моста, который вы обычно используете для вызова objc из swift.
источник
Вы можете использовать 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); };
Swift:
class ViewController: UIViewController { func send(friend: Contact) { let c = Contact() contact.sendMessage("Hello", friend) contact.addTags(["a","b","c"]) contact.addFriends([friend]) } }
источник