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?

EhTd
sumber

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 ++.

Rob Napier
sumber
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

Arsitektur Swift
sumber
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.

Gian Luigi Romita
sumber
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;
}
Dan G
sumber
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

pengecoran
sumber
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

Sandy
sumber
8

Swift tidak kompatibel langsung dengan C ++. Anda dapat mengatasi masalah ini dengan membungkus kode C ++ Anda dengan Objective-C, dan menggunakan pembungkus Objective C di Swift.

Austin
sumber
Inilah yang saya lakukan. Saya menulis artikel tentang bagaimana mengintegrasikan c ++ dengan proyek cepat: learningswift.brightdigit.com/integrating-c-plus-plus-plus-swift
leogdion
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

James Mart
sumber
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;
}
// */
snake5
sumber
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.

Fattie
sumber
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

Anatoli P
sumber
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

Ryan Heitner
sumber