Bisakah saya mencampur Swift dengan C ++? Seperti file Objective-C .mm


131

Saya baru saja mengubah file .m saya menjadi .mm dan menggunakan C ++. Apakah ada cara untuk melakukan hal yang sama dengan Swift?

Jawaban:


111

Tidak. Ketika Anda beralih dari .m ke .mm Anda sebenarnya beralih dari Objective-C ke bahasa yang berbeda (yang memiliki banyak perbedaan halus) yang disebut Objective-C ++. Jadi Anda tidak benar-benar menggunakan C ++; Anda menggunakan Objective-C ++ yang menerima sebagian besar C ++ sebagai input (dengan cara yang sama seperti C ++ menerima sebagian besar tetapi tidak semua C sebagai input). Ketika saya mengatakan itu bukan C ++, pertimbangkan file C ++ yang menyertakan variabel bernama nil(yang legal C ++) dan kemudian coba kompilasi sebagai Objective-C ++.

Swift tidak memiliki hubungan yang sama. Ini bukan superset dari C atau C ++, dan Anda tidak bisa langsung menggunakan salah satu .swiftfile.

"Menggunakan Swift dengan Cocoa dan Objective-C" juga memberi tahu kita:

Anda tidak dapat mengimpor kode C ++ langsung ke Swift. Sebagai gantinya, buat pembungkus Objective-C atau C untuk kode C ++.


93
Sebenarnya cukup menyebalkan - kita semua dengan aplikasi Kakao yang menggabungkan basis kode C / C ++ sekarang harus mengelola proyek yang ditulis dalam 3 bahasa ....
Jay

6
Saya menyarankan Objective-c ++ bukan bahasa yang berbeda tetapi campuran c ++ dan Objective-c perbedaannya halus tetapi masih ada
amar

1
Bagaimana "nil" legal C ++? Tidak ada hal seperti itu (setidaknya dalam standar c ++). Berikan contoh lain
rewolf

3
Tetapi dengan ObjC Anda hanya bisa membuka .mmfile Anda dan (hampir) selesai. Tidak demikian halnya dengan Swift.
chakrit

6
@rewolf, saya pikir maksudnya variabel bernama nil, sepertiint nil
Luke

165

Kebingungan mungkin berasal dari asumsi bahwa hanya mengubah ekstensi file dari .mmenjadi .mmyang Anda butuhkan untuk menjembatani bahasa, ketika, pada kenyataannya, itu tidak melakukan hal semacam itu. Bukan .mmyang menyebabkan gesekan dengan .cpp, melainkan .htajuk yang pasti tidak menjadi C++tajuk.


Proyek yang sama: Ya.

Dalam proyek yang sama , Anda dapat dengan senang hati mencampur C , C ++ , Objective-C , Objective C ++ , Swift , dan bahkan Assembly .

  1. ...Bridging-Header.h: Anda mengekspos C , Objective-C dan Objective-C ++ ke Swift menggunakan jembatan ini
  2. <ProductModuleName>-Swift.h: memperlihatkan secara otomatis kelas Swift Anda yang ditandai dengan @objcke Objective-C
  3. .h: ini adalah bagian yang sulit, karena mereka secara ambigu digunakan untuk semua rasa C , ++ atau tidak, Objektif atau tidak. Ketika a .htidak mengandung kata kunci C ++ tunggal , seperti class, itu dapat ditambahkan ke ...Bridging-Header.h, dan akan memaparkan fungsi apa pun yang sesuai .c atau .cpp fungsionalitas yang dinyatakannya. Kalau tidak, header itu harus dibungkus dengan API C atau Objective-C murni .

File yang sama: Tidak.

Dalam file yang sama , Anda tidak dapat mencampur semua 5. Dalam file sumber yang sama :

  1. .swift: Anda tidak dapat mencampur Swift dengan apa pun
  2. .m: Anda dapat mencampur Objective-C dengan C . ( @Vinzzz )
  3. .mm: Anda dapat mencampur Objective-C dengan C ++ . Jembatan ini adalah Objective-C ++ . ( @Vinzzz ).
  4. .c: pure C
  5. .cpp: Anda dapat mencampur C ++ & Assembly ( @Vality )
  6. .h: di mana-mana dan ambigu C , C ++ , Objective-C atau Objective-C ++ , jadi jawabannya tergantung.

Referensi


1
Koreksi: Dalam file sumber .m yang sama , Objective-C menjadi superset C yang ketat, Anda BISA mencampur Objective-C dan C ...
Vinzzz

1
Tidak masalah, saya bahkan tidak peduli dengan kredit, selama jawabannya adalah yang benar;) BTW, .mm adalah untuk mencampur Objective-C dan C ++ (C dan C ++ adalah dua hal yang berbeda, terlepas dari namanya )
Vinzzz

1
Saya akan menyebutkan bahwa tidak seperti objektif C, C ++ bukan superset C sehingga Anda tidak dapat mencampur C dan C ++ dalam file .cpp. Hanya C ++ dan assembly.
Vality

1
Seandainya ada orang yang menemukan bahwa jawaban terperinci ini tidak cukup membantu ketika mencoba mengekspos file Swift ke dalam file Objective-C / C ++ mereka (Xcode mengeluh bahwa file header Swift tidak ditemukan). Saya menemukan bahwa saya harus mengimpor "ProductName / ProductModuleName-Swift.h" di file sumber Objective-C / C ++ saya. Saya menemukan ini agak terkubur di: developer.apple.com/library/ios/documentation/Swift/Conceptual/…
AeroBuffalo

Poin yang bagus. Untuk proyek kerja yang menggabungkan bahasa-bahasa ini, silakan lihat stackoverflow.com/a/32546879/218152 .
SwiftArchitect

72

Saya menulis proyek Xcode 6 sederhana yang menunjukkan cara menggabungkan C ++, Objective C dan kode Swift:

https://github.com/romitagl/share/tree/master/C-ObjC-Swift/Performance_Console

Khususnya contoh memanggil fungsi Objective C dan C ++ dari Swift.

Kuncinya adalah membuat header bersama Project-Bridging-Header.h dan meletakkan header Objective C di sana.

Silakan unduh proyek sebagai contoh lengkap.


Terima kasih untuk Gian ini!
Jason Elwood

Terima kasih atas contoh ini, tetapi jika saya ingin memindahkan #import "CPlusPlus.h" dari ObjCtoCPlusPlus.mm ke file ObjCtoCPlusPlus.h, kompiler mengembalikan kesalahan ini: <unknown>: 0: error: gagal mengimpor menjembatani header ' /Pengguna/Ale/Downloads/share-master/C-ObjC-Swift/Performance_Console/Performance_Console/Performance_Console-Bridging-Header.h 'mungkinkah memindahkan impor ini ke file header?
Alessandro Pirovano

@API: Tidak, Anda tidak mengerti intinya. ObjCtoCPlusPlus.h/ `` .mm` ada untuk tujuan tunggal menyediakan antarmuka Ob-C untuk kode C ++ — itu adalah jembatan, yang merupakan komponen yang diperlukan di sini. Biarkan menyertakan di mana mereka berada, dan tambahkan metode dalam ObjCtoCPlusPlus.…file untuk setiap metode C ++ yang perlu Anda akses. Anda sebaiknya membaca lebih dari sourcemaking.com/design_patterns/adapter
Slipp D. Thompson

Saya mengunduh contoh Anda dan ini fantastis untuk fungsi STATIC yang ditawarkan kelas sebagai contoh, tetapi saya tidak dapat mengatur contoh untuk fungsi non-statis tambahan yang akan digunakan dari luar ... Apakah itu juga mungkin? (Saya melakukan pekerjaan rumah C ++ saya beberapa dekade yang lalu ... Saya bukan pensil paling tajam dari kotak sekarang)
Isaac

31

Anda juga dapat melewatkan file Objective-C di antaranya. Cukup tambahkan file header C dengan file sumber .cpp. Hanya memiliki deklarasi C dalam file header dan sertakan kode C ++ apa pun dalam file sumber. Kemudian sertakan file header C di ** - Bridging-Header.h.

Contoh berikut mengembalikan pointer ke objek C ++ (struct Foo) sehingga Swift dapat menyimpan dalam COpaquePointer alih-alih mendefinisikan struct Foo di ruang global.

File Foo.h (dilihat oleh Swift - termasuk dalam file bridging)

#ifndef FOO_H
#define FOO_H

// Strictly C code here.
// 'struct Foo' is opaque (the compiler has no info about it except that 
// it's a struct we store addresses (pointers) to it.
struct Foo* foo_create();
void foo_destroy(struct Foo* foo);

#endif

File sumber di dalam Foo.cpp (tidak terlihat oleh Swift):

extern "C"
{
#include "Foo.h"
}
#include <vector>

using namespace std;

// C++ code is fine here. Can add methods, constructors, destructors, C++ data members, etc.
struct Foo
{
   vector<int> data;
};

struct Foo* foo_create()
{
   return new Foo;
}

void foo_destroy(struct Foo* foo)
{
    delete foo;
}

1
Jawaban ini layak cara yang lebih upvotes. Sangat bermanfaat.
rsp1984

Ini adalah pertama kalinya saya melihat extern "C"membungkus header di tempat itu dimasukkan daripada #ifdef'ed dalam file header itu sendiri. Cemerlang!
dcow

27

Saya baru saja membuat proyek contoh kecil menggunakan Swift, Objective-C dan C ++. Ini adalah demo tentang cara menggunakan jahitan OpenCV di iOS. API OpenCV adalah C ++ sehingga kami tidak dapat berbicara langsung dari Swift. Saya menggunakan kelas pembungkus kecil yang file implementasinya adalah Objective-C ++. File Header bersih Objective-C, sehingga Swift dapat berbicara dengan ini secara langsung. Anda harus berhati-hati untuk tidak mengimpor file C ++-ish secara tidak langsung ke header yang berinteraksi dengan Swift.

Proyeknya ada di sini: https://github.com/foundry/OpenCVSwiftStitch


Saya pikir ini menjawab masalah yang saya tekan hari ini mencoba menggunakan perpustakaan pihak ke-3 KudanCV dengan Swift. Heading bridging saya mengimpor file .h mereka yang berisi impor ke <memory> <strings> dan <vectors> yang saya kira berasal dari pustaka atau file C ++, akibatnya kode Swift saya tidak dapat dikompilasi. Saya akan berterima kasih jika seseorang dapat memberi tahu saya jika ada cara untuk mengatasi ini ... atau jika saya harus menulis ulang semua kode saya di Objective-C
Rocket Garden

1
@RocketGarden - File header KudanCV adalah C ++. Anda bisa menulis pembungkus yang bekerja dengan cara yang sama seperti kelas pembungkus contoh saya. ATAU Anda menulis ulang bagian-bagian aplikasi Anda yang perlu berbicara dengan KudanCV di objektif-C ++ (dengan header Objective-C). Anda tidak perlu menulis ulang bagian-bagian dari proyek Anda yang tidak peduli dengan KudanCV.
pengecoran

Terima kasih untuk itu, saya menyadarinya sekitar 5 menit kemudian, tetapi berguna untuk merekamnya untuk orang lain.
Rocket Garden

13

Inilah upaya saya di alat dentang untuk mengotomatisasi komunikasi C ++ / swift. Anda dapat menginstal kelas C ++ dari swift, mewarisi dari kelas C ++ dan bahkan menimpa metode virtual di swift.
Ini akan mem-parsing kelas C ++ yang ingin Anda ekspor ke swift dan menghasilkan jembatan Objective-C / Objective-C ++ secara otomatis.

https://github.com/sandym/swiftpp




4

Tidak, tidak dalam satu file.

Namun, Anda dapat menggunakan C ++ di Swift Projects tanpa memerlukan pustaka atau kerangka kerja statis. Seperti yang dikatakan orang lain, kuncinya adalah membuat header penghubung Objective-C yang # termasuk header C ++ yang kompatibel dengan C yang ditandai sebagai C kompatibel dengan trik "C" {} eksternal .

Video tutorial: https://www.youtube.com/watch?v=0x6JbiphNS4


2

Jawaban lain sedikit tidak akurat. Anda sebenarnya dapat mencampur Swift dan [Objective-] C [++] dalam file yang sama, meskipun tidak seperti yang Anda harapkan.

File ini (c.swift) mengkompilasi ke executable yang valid dengan keduanya swiftc c.swiftdanclang -x objective-c c.swift

/* /* */
#if 0
// */
import Foundation
print("Hello from Swift!")
/* /* */
#endif
#include <stdio.h>
int main()
{
    puts("Hello from C!");
    return 0;
}
// */

Kode sampel Anda dalam C bukan C ++. Lebih baik pergi dengan contoh IMHO <iostream>.
kakyo

2

Salah satu trik (dari banyak) adalah itu

Anda memerlukan tajuk terpisah untuk menjembatani file obj-c ++ Anda ...

Anda tidak bisa begitu saja membuang @interface dan @implementation dalam file .mm yang sama dengan yang biasa dilakukan.

Jadi dalam file header bridging yang Anda miliki

#import "Linkage.hpp"

Linkage.hpp memiliki @interface untuk Linkage dan Linkage.mm memiliki @implementation untuk .mm

Lalu

... Anda sebenarnya tidak mencantumkan "yourCpp.hpp" di Linkage.hpp.

Anda hanya memasukkan #include "yourCpp.hpp"file Linkage.mm, bukan di file Linkage.hpp.

Dalam banyak contoh / tutorial online, penulis cukup meletakkan @interface dan @implementation dalam file .mm yang sama, seperti yang sering dilakukan orang.

Itu akan bekerja dalam contoh penghubung cpp yang sangat sederhana, tetapi,

Masalahnya adalah:

jika yourCpp.hpp Anda memiliki fitur c ++ sama sekali yang pasti (seperti, baris pertama #include <something>), maka prosesnya akan gagal.

Tetapi jika Anda tidak memiliki #include "yourCpp.hpp"di header file Linkage (tidak apa-apa untuk memilikinya dalam file .mm, jelas Anda harus) - itu berfungsi.

Sekali lagi ini sayangnya hanya satu tip dalam keseluruhan proses.


1

Dalam hal ini bermanfaat bagi siapa pun, saya juga memiliki tutorial singkat tentang memanggil perpustakaan statis C ++ sederhana dari utilitas baris perintah Swift yang sepele. Ini adalah bukti yang sangat sederhana dari potongan kode konsep.

Tidak ada Objective-C yang terlibat, hanya Swift dan C ++. Kode dalam pustaka C ++ disebut oleh pembungkus C ++ yang mengimplementasikan fungsi dengan tautan "C" eksternal. Fungsi itu kemudian direferensikan di header bridging dan dipanggil dari Swift.

Lihat http://www.swiftprogrammer.info/swift_call_cpp.html


1

Saya memberikan tautan ke SE-0038 di sumber resmi, dijelaskan sebagai Ini mempertahankan proposal untuk perubahan dan peningkatan yang terlihat oleh pengguna ke Bahasa Pemrograman Swift.

Status pada hari ini adalah bahwa ini adalah permintaan fitur yang telah diterima tetapi belum dijadwalkan.

Tautan ini dimaksudkan untuk mengarahkan siapa pun yang mencari fitur ini ke arah yang benar

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.