Posso mescolare Swift con C ++? Come i file Objective-C .mm


131

Ho appena cambiato i miei file .m in .mm e uso C ++. C'è un modo per fare lo stesso con Swift?

Risposte:


111

No. Quando passi da .m a .mm stai effettivamente passando da Objective-C a un linguaggio diverso (che presenta molte differenze sottili) chiamato Objective-C ++. Quindi non stai davvero usando C ++; stai usando Objective-C ++ che accetta la maggior parte del C ++ come input (nello stesso modo in cui C ++ accetta la maggior parte, ma non tutti i C come input). Quando dico che non è proprio C ++, considera un file C ++ che include una variabile denominata nil(che è C ++ legale) e quindi prova a compilarlo come Objective-C ++.

Swift non ha la stessa relazione. Non è un superset di C o C ++ e non è possibile utilizzarlo direttamente in un .swiftfile.

"Uso di Swift con Cocoa e Objective-C" ci dice anche:

Non è possibile importare il codice C ++ direttamente in Swift. Invece, creare un wrapper Objective-C o C per il codice C ++.


93
Abbastanza fastidioso in realtà - tutti noi con le app Cocoa che incorporano basi di codice C / C ++ ora dobbiamo mantenere progetti scritti in 3 lingue ....
Jay

6
Suggerisco che Objective-c ++ non è un linguaggio diverso, ma un mix di c ++ e Objective-c differenza è sottile ma è ancora lì
amar

1
In che modo il C ++ "zero" è legale? Non esiste nulla del genere (almeno in c ++ standard) Fornisci un altro esempio
rewolf,

3
Ma con ObjC puoi semplicemente andare ai .mmtuoi file ed essere (quasi) fatto. Non così con Swift.
chakrit,

6
@rewolf, penso che significhi una variabile chiamata nil, comeint nil
Luca

165

La confusione può derivare dal presupposto che semplicemente cambiare un'estensione di file da .ma .mmè tutto ciò che serve per colmare le lingue, quando, in realtà, non fa nulla del genere. Non è quello .mmche causa attrito .cpp, è l' .hintestazione che non deve essere positivamente C++un'intestazione.


Stesso progetto: Sì.

Nello stesso progetto, puoi tranquillamente mescolare C , C ++ , Objective-C , Objective C ++ , Swift e persino Assembly .

  1. ...Bridging-Header.h: esponi C , Objective-C e Objective-C ++ su Swift usando questo bridge
  2. <ProductModuleName>-Swift.h: Espone automaticamente i tuoi Swift classi contrassegnati con @objca Objective-C
  3. .h: questa è la parte difficile, dal momento che sono ambiguamente usati per tutti i gusti di C , ++ o no, Obiettivo o no. Quando a .hnon contiene una singola parola chiave C ++ , come class, può essere aggiunta a ...Bridging-Header.h, ed esporrà qualunque funzione le corrispondenti .c o .cpp funzionalità che dichiara. Altrimenti, quell'intestazione deve essere racchiusa in un'API C o Objective-C pura .

Stesso file: No.

Nello stesso file, non è possibile mescolare tutti 5. Nello stesso file di origine :

  1. .swift: non puoi mescolare Swift con niente
  2. .m: Potete mescolare Objective-C con C . ( @Vinzzz )
  3. .mm: puoi mescolare Objective-C con C ++ . Questo bridge è Objective-C ++ . ( @Vinzzz ).
  4. .c: puro C
  5. .cpp: puoi mescolare C ++ e Assembly ( @Vality )
  6. .h: onnipresente e ambiguo C , C ++ , Objective-C o Objective-C ++ , quindi la risposta è che dipende.

Riferimenti


1
Correzione: nello stesso file sorgente .m , essendo Objective-C un superset C rigoroso, PUOI mescolare Objective-C e C ...
Vinzzz,

1
Nessun problema, non mi interessa nemmeno il merito, purché la risposta sia quella corretta;) A proposito, .mm è per mescolare Objective-C e C ++ (C e C ++ sono due cose diverse, nonostante il nome )
Vinzzz,

1
Vorrei menzionare che, diversamente dall'obiettivo C, C ++ non è un superset C, quindi non è possibile mescolare sia C che C ++ in un file .cpp. Solo C ++ e assembly.
Validità

1
Nel caso in cui qualcuno scopra che questa risposta ben dettagliata non aiuta del tutto quando si tenta di esporre i file Swift nel proprio file Objective-C / C ++ (Xcode si lamenta che il file di intestazione Swift non è stato trovato). Ho scoperto che dovevo importare "ProductName / ProductModuleName-Swift.h" nel mio file sorgente Objective-C / C ++. L'ho trovato un po 'sepolto su: developer.apple.com/library/ios/documentation/Swift/Conceptual/…
AeroBuffalo

Buon punto. Per un progetto di lavoro che mescola queste lingue, dai un'occhiata a stackoverflow.com/a/32546879/218152 .
SwiftArchitect,

72

Ho scritto un semplice progetto Xcode 6 che mostra come mescolare codice C ++, Objective C e codice Swift:

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

In particolare, l'esempio chiama Swift da un obiettivo C e una funzione C ++.

La chiave è creare un'intestazione condivisa Project-Bridging-Header.h e inserire lì le intestazioni dell'Obiettivo C.

Si prega di scaricare il progetto come esempio completo.


Grazie per questo Gian!
Jason Elwood,

Grazie per questo esempio, ma se voglio spostare #import "CPlusPlus.h" dal file ObjCtoCPlusPlus.mm al file ObjCtoCPlusPlus.h, il compilatore restituisce questo errore: <sconosciuto>: 0: errore: impossibile importare l'intestazione ponte " /Users/Ale/Downloads/shared-master/C-ObjC-Swift/Performance_Console/Performance_Console/Performance_Console-Bridging-Header.h 'è possibile spostare questa importazione nel file di intestazione?
Alessandro Pirovano,

@API: No, ti manca il punto. ObjCtoCPlusPlus.h/ `` .mm` esiste al solo scopo di fornire un'interfaccia Ob-C al codice C ++ - è il bridge, che è un componente necessario qui. Lasciare le inclusioni dove si trovano e aggiungere un metodo nei ObjCtoCPlusPlus.…file per ciascun metodo C ++ a cui è necessario accedere. Faresti bene a leggere su sourcemaking.com/design_patterns/adapter
Slipp D. Thompson

Ho scaricato il tuo esempio ed è fantastico per la funzione STATICA che la classe offre come esempio, ma non riesco ad adattare l'esempio per una funzione non statica aggiuntiva da utilizzare dall'esterno ... È anche possibile? (Ho fatto i miei compiti in C ++ decenni fa ... Non sono la matita più affilata della scatola in questo momento)
Isaac

31

Puoi anche saltare il file Objective-C tra. Basta aggiungere un file di intestazione C con un file di origine .cpp. Includere solo dichiarazioni C nel file di intestazione e includere qualsiasi codice C ++ nel file di origine. Quindi includere il file di intestazione C in ** - Bridging-Header.h.

L'esempio seguente restituisce un puntatore a un oggetto C ++ (struct Foo) in modo che Swift possa archiviare in un COpaquePointer invece di avere Struct Foo definito nello spazio globale.

File Foo.h (visto da Swift - incluso nel file ponte)

#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

All'interno del file sorgente Foo.cpp (non visto da 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
Questa risposta merita modo più upvotes. Davvero utile.
rsp1984,

Questa è la prima volta che vedo extern "C"avvolgere l'intestazione nel punto in cui è inclusa anziché #ifdef"ed" nel file di intestazione stesso. Brillante!
dc

27

Ho appena realizzato un piccolo esempio di progetto usando Swift, Objective-C e C ++. È una demo di come utilizzare le cuciture OpenCV in iOS. L'API OpenCV è C ++ quindi non possiamo parlarne direttamente da Swift. Uso una piccola classe wrapper il cui file di implementazione è Objective-C ++. Il file Header è pulito Objective-C, quindi Swift può parlarne direttamente. Bisogna fare attenzione a non importare indirettamente alcun file C ++ nelle intestazioni con cui Swift interagisce.

Il progetto è qui: https://github.com/foundry/OpenCVSwiftStitch


Penso che questo risponda a un problema che ho riscontrato oggi cercando di utilizzare una libreria di terze parti KudanCV con Swift. La mia intestazione ponte importa il loro file .h che contiene le importazioni in <memoria> <stringhe> e <vettori> che immagino provengano da librerie o file C ++, di conseguenza il mio codice Swift non verrà compilato. Le sarei grato se qualcuno potesse dirmi se c'è un modo per aggirare questo ... o se devo riscrivere tutto il mio codice in Objective-C
Rocket Garden il

1
@RocketGarden - Il file di intestazione di KudanCV è C ++. Potresti scrivere un wrapper che funziona allo stesso modo della mia classe wrapper di esempio. OPPURE riscrivi quelle parti della tua app che devono parlare con KudanCV in object-C ++ (con intestazioni Objective-C). Non dovrai riscrivere quelle parti del tuo progetto che non riguardano KudanCV.
fonderia,

Grazie, l'ho realizzato circa 5 minuti dopo, ma è utile averlo registrato per gli altri.
Rocket Garden,

13

Ecco il mio tentativo di uno strumento clang per automatizzare la comunicazione C ++ / swift. Puoi instanciare le classi C ++ da swift, ereditare dalla classe C ++ e persino sovrascrivere i metodi virtuali in swift.
Analizzerà la classe C ++ che si desidera esportare in modo rapido e genererà automaticamente il bridge Objective-C / Objective-C ++.

https://github.com/sandym/swiftpp




4

No, non in un singolo file.

Tuttavia, è possibile utilizzare C ++ nei progetti Swift senza la necessità di una libreria o framework statici. Come altri hanno già detto, la chiave è creare un'intestazione bridge Objective-C che includa le intestazioni C ++ compatibili con C che sono contrassegnate come C compatibili con il trucco esterno "C" {} .

Esercitazione video: https://www.youtube.com/watch?v=0x6JbiphNS4


2

Altre risposte sono leggermente imprecise. Puoi effettivamente mescolare sia Swift che [Objective-] C [++] nello stesso file, anche se non esattamente come ti aspetteresti.

Questo file (c.swift) viene compilato in un eseguibile valido con entrambi swiftc c.swifteclang -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;
}
// */

Il codice di esempio è in C non in C ++. Meglio andare con un IMHO <iostream> di esempio.
kakyo,

2

Un trucco (di molti) è quello

Hai bisogno di un'intestazione separata per il tuo file obj-c ++ a ponte ...

Non puoi semplicemente lanciare @interface e @implementation nello stesso file .mm come si fa normalmente.

Quindi nel tuo file di intestazione ponte hai

#import "Linkage.hpp"

Linkage.hpp ha @interface per Linkage e Linkage.mm ha @implementation per .mm

E poi

... in realtà non #include "yourCpp.hpp" in Linkage.hpp.

#include "yourCpp.hpp"Inserisci solo il file Linkage.mm, non il file Linkage.hpp.

In molti esempi / tutorial online, lo scrittore inserisce semplicemente @interface e @implementation nello stesso file .mm, come si fa spesso.

Funzionerà in esempi di bridge cpp molto semplici, ma,

Il problema è:

se yourCpp.hpp ha funzionalità c ++ che sicuramente avrà (come la prima riga #include <something>), il processo fallirà.

Ma se semplicemente non hai il file di intestazione#include "yourCpp.hpp" Linkage (va bene averlo nel file .mm, ovviamente dovrai farlo) - funziona.

Ancora una volta, questo è purtroppo solo un suggerimento nell'intero processo.


1

Se questo è utile a chiunque, ho anche un breve tutorial su come chiamare una semplice libreria statica C ++ da una banale utility da riga di comando Swift. Questa è una prova davvero concisa del concetto di codice.

Nessun obiettivo-C coinvolto, solo Swift e C ++. Il codice in una libreria C ++ viene chiamato da un wrapper C ++ che implementa una funzione con collegamento "C" esterno. Tale funzione viene quindi indicata nell'intestazione del bridge e chiamata da Swift.

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


1

Sto fornendo un collegamento a SE-0038 nella risorsa ufficiale, descritto come Questo mantiene proposte di modifiche e miglioramenti visibili all'utente al linguaggio di programmazione Swift.

Lo stato attuale è che questa è la richiesta di funzionalità che è stata accettata ma non ancora pianificata.

Questo link ha lo scopo di guidare chiunque cerchi questa funzione nella giusta direzione

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.