Saya memiliki perpustakaan kelas yang signifikan yang ditulis dalam C ++. Saya mencoba memanfaatkannya melalui beberapa jenis penghubung dalam Swift daripada menulis ulang sebagai kode Swift. Motivasi utamanya adalah bahwa kode C ++ mewakili pustaka inti yang digunakan pada banyak platform. Secara efektif, saya hanya membuat UI berbasis Swift untuk memungkinkan fungsionalitas inti berfungsi di bawah OS X.
Ada pertanyaan lain yang menanyakan, "Bagaimana cara memanggil fungsi C ++ dari Swift." Ini bukan pertanyaan saya. Untuk menjembatani ke fungsi C ++, berikut ini berfungsi dengan baik:
Tentukan header penghubung melalui "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 */
Kode Swift sekarang dapat memanggil fungsi secara langsung
let type = String.fromCString(imageType(filename))
let dump = String.fromCString(hexdump(filename))
Pertanyaan saya lebih spesifik. Bagaimana cara saya membuat instance dan memanipulasi Kelas C ++ dari dalam Swift? Saya tidak dapat menemukan apa pun yang dipublikasikan tentang ini.
Jawaban:
Saya telah menyusun jawaban yang bisa dikelola dengan sempurna. Seberapa bersih Anda menginginkan hal ini sepenuhnya didasarkan pada seberapa banyak pekerjaan yang ingin Anda lakukan.
Pertama, ambil kelas C ++ Anda dan buat fungsi "pembungkus" C untuk berinteraksi dengannya. Misalnya, jika kita memiliki kelas C ++ ini:
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); };
Kami kemudian mengimplementasikan fungsi C ++ ini:
#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; }
Header jembatan kemudian berisi:
#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 */
Dari Swift, kita sekarang dapat membuat instance objek dan berinteraksi dengannya seperti:
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!
Jadi, seperti yang Anda lihat, solusinya (yang sebenarnya cukup sederhana) adalah membuat pembungkus yang akan membuat instance objek dan mengembalikan pointer ke objek itu. Ini kemudian dapat dikirimkan kembali ke fungsi pembungkus yang dapat dengan mudah memperlakukannya sebagai objek yang sesuai dengan kelas itu dan memanggil fungsi anggota.
Menjadikannya Lebih Bersih
Meskipun ini adalah awal yang fantastis dan membuktikan bahwa sangat layak untuk menggunakan kelas C ++ yang ada dengan jembatan yang sepele, ini bahkan bisa lebih bersih.
Membersihkan ini berarti kita menghapus
UnsafeMutablePointer<Void>
bagian tengah kode Swift kita dan merangkumnya ke dalam kelas Swift. Pada dasarnya, kami menggunakan fungsi pembungkus C / C ++ yang sama tetapi menghubungkannya dengan kelas Swift. Kelas Swift mempertahankan referensi objek dan pada dasarnya hanya meneruskan semua panggilan referensi metode dan atribut melalui jembatan ke objek C ++!Setelah melakukan ini, semua kode penghubung benar-benar dikemas dalam kelas Swift. Meskipun kami masih menggunakan C bridge, kami secara efektif menggunakan objek C ++ secara transparan tanpa harus menggunakan pengodean ulang di Objective-C atau Objective-C ++.
sumber
Swift tidak memiliki interop C ++ saat ini. Ini adalah tujuan jangka panjang, tetapi sangat tidak mungkin terjadi dalam waktu dekat.
sumber
Selain solusi Anda sendiri, ada cara lain untuk melakukannya. Anda dapat memanggil atau langsung menulis kode C ++ di objektif-c ++.
Jadi Anda dapat membuat pembungkus objektif-C ++ di atas kode C ++ Anda dan membuat antarmuka yang sesuai.
Kemudian panggil kode tujuan-C ++ dari kode swift Anda. Untuk dapat menulis kode objektif-C ++ Anda mungkin harus mengganti nama ekstensi file dari .m menjadi .mm
Jangan lupa untuk melepaskan memori yang dialokasikan oleh objek C ++ Anda jika cocok.
sumber
Anda dapat menggunakan Scapix Language Bridge untuk secara otomatis menjembatani C ++ ke Swift (di antara bahasa lain). Kode jembatan secara otomatis dibuat dengan cepat langsung dari file header C ++. Berikut ini contohnya :
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); };
Cepat:
class ViewController: UIViewController { func send(friend: Contact) { let c = Contact() contact.sendMessage("Hello", friend) contact.addTags(["a","b","c"]) contact.addFriends([friend]) } }
sumber
Seperti jawaban lain yang disebutkan, menggunakan ObjC ++ untuk berinteraksi jauh lebih mudah. Cukup beri nama file Anda .mm, bukan .m dan xcode / clang, memberi Anda akses ke c ++ di file itu.
Perhatikan bahwa ObjC ++ tidak mendukung pewarisan C ++. Saya Anda ingin membuat subclass kelas c ++ di ObjC ++, Anda tidak bisa. Anda harus menulis subclass dalam C ++ dan membungkusnya di sekitar kelas ObjC ++.
Kemudian gunakan header penghubung yang biasanya Anda gunakan untuk memanggil objc dari swift.
sumber