Posiadam pokaźną bibliotekę zajęć napisanych w C ++. Próbuję je wykorzystać przez jakiś rodzaj mostu w Swift, zamiast przepisać je jako kod Swift. Podstawową motywacją jest to, że kod C ++ reprezentuje podstawową bibliotekę używaną na wielu platformach. W rzeczywistości tworzę interfejs użytkownika oparty na Swift, aby umożliwić działanie podstawowych funkcji w systemie OS X.
Pojawiają się inne pytania: „Jak wywołać funkcję C ++ z języka Swift”. To nie jest moje pytanie. Aby przejść do funkcji C ++, poniższe działa dobrze:
Zdefiniuj nagłówek mostkujący przez „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 */
Szybki kod może teraz bezpośrednio wywoływać funkcje
let type = String.fromCString(imageType(filename))
let dump = String.fromCString(hexdump(filename))
Moje pytanie jest bardziej szczegółowe. Jak mogę utworzyć instancję i manipulować klasą C ++ z poziomu Swift? Nie mogę znaleźć niczego opublikowanego na ten temat.
Odpowiedzi:
Opracowałem doskonale wykonalną odpowiedź. Stopień czystości zależy wyłącznie od tego, ile pracy chcesz wykonać.
Najpierw weź swoją klasę C ++ i utwórz funkcje „wrappera” języka C, aby z nią współpracować. Na przykład, jeśli mamy tę klasę 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); };
Następnie implementujemy te funkcje 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; }
Nagłówek mostu zawiera wtedy:
#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 */
W Swift możemy teraz utworzyć instancję obiektu i wchodzić z nim w interakcję w następujący sposób:
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!
Tak więc, jak widać, rozwiązaniem (które w rzeczywistości jest raczej proste) jest utworzenie opakowań, które utworzą instancję obiektu i zwrócą wskaźnik do tego obiektu. Można to następnie przekazać z powrotem do funkcji opakowujących, które mogą z łatwością traktować go jako obiekt zgodny z tą klasą i wywoływać funkcje składowe.
Czystsze
Chociaż jest to fantastyczny początek i udowadnia, że użycie istniejących klas C ++ z trywialnym mostkiem jest całkowicie wykonalne, może być nawet czystsze.
Oczyszczenie tego oznaczałoby po prostu usunięcie
UnsafeMutablePointer<Void>
kodu ze środka naszego kodu Swift i zamknięcie go w klasie Swift. Zasadniczo używamy tych samych funkcji opakowujących C / C ++, ale łączymy je z klasą Swift. Klasa Swift przechowuje odwołanie do obiektu i po prostu przekazuje wszystkie wywołania metod i atrybutów przez most do obiektu C ++!Po wykonaniu tej czynności cały kod mostkujący jest całkowicie zamknięty w klasie Swift. Mimo że nadal używamy mostka C, efektywnie używamy obiektów C ++ w sposób przejrzysty bez konieczności ponownego kodowania ich w Objective-C lub Objective-C ++.
źródło
Swift nie ma obecnie współdziałania z C ++. Jest to cel długoterminowy, ale jest mało prawdopodobne, aby pojawił się w najbliższej przyszłości.
źródło
Oprócz własnego rozwiązania istnieje inny sposób, aby to zrobić. Możesz wywołać lub bezpośrednio napisać kod C ++ w Objective-C ++.
Możesz więc utworzyć opakowanie obiektywnego C ++ na wierzchu kodu C ++ i stworzyć odpowiedni interfejs.
Następnie wywołaj kod Objective-C ++ z kodu Swift. Aby móc napisać kod obiektywnego C ++, może być konieczna zmiana rozszerzenia pliku z .m na .mm
Nie zapomnij zwolnić pamięci przydzielonej przez obiekty C ++, gdy jest to odpowiednie.
źródło
Jak wspomniano w innej odpowiedzi, używanie ObjC ++ do interakcji jest znacznie łatwiejsze. Po prostu nazwij swoje pliki .mm zamiast .m i xcode / clang, daje ci dostęp do c ++ w tym pliku.
Zauważ, że ObjC ++ nie obsługuje dziedziczenia w C ++. Jeśli chcesz podklasować klasę c ++ w ObjC ++, nie możesz. Będziesz musiał napisać podklasę w C ++ i owinąć ją wokół klasy ObjC ++.
Następnie użyj nagłówka mostkowania, którego normalnie używałbyś do wywołania objc ze swift.
źródło
Możesz użyć Scapix Language Bridge, aby automatycznie połączyć C ++ ze Swift (między innymi). Kod mostu generowany automatycznie w locie bezpośrednio z plików nagłówkowych C ++. Oto przykład :
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); };
Szybki:
class ViewController: UIViewController { func send(friend: Contact) { let c = Contact() contact.sendMessage("Hello", friend) contact.addTags(["a","b","c"]) contact.addFriends([friend]) } }
źródło