Kann ich Swift mit C ++ mischen? Wie die Objective-C .mm-Dateien

131

Ich habe gerade meine .m-Dateien in .mm geändert und verwende C ++. Gibt es eine Möglichkeit, dasselbe mit Swift zu tun?

EhTd
quelle

Antworten:

111

Nein. Wenn Sie von .m zu .mm wechseln, wechseln Sie tatsächlich von Objective-C zu einer anderen Sprache (die viele subtile Unterschiede aufweist) namens Objective-C ++. Sie verwenden C ++ also nicht wirklich. Sie verwenden Objective-C ++, das die meisten C ++ als Eingabe akzeptiert (genauso wie C ++ die meisten, aber nicht alle C als Eingabe akzeptiert). Wenn ich sage, dass es nicht ganz C ++ ist, betrachten Sie eine C ++ - Datei, die eine Variable mit dem Namen nil(was legal C ++ ist) enthält, und versuchen Sie dann, diese als Objective-C ++ zu kompilieren.

Swift hat nicht die gleiche Beziehung. Es ist keine Obermenge von C oder C ++, und Sie können auch keine direkt in einer .swiftDatei verwenden.

"Swift mit Kakao und Objective-C verwenden" sagt uns auch:

Sie können C ++ - Code nicht direkt in Swift importieren. Erstellen Sie stattdessen einen Objective-C- oder C-Wrapper für C ++ - Code.

Rob Napier
quelle
93
Eigentlich ziemlich nervig - wir alle mit Cocoa-Apps, die C / C ++ - Codebasen enthalten, müssen jetzt Projekte verwalten, die in 3 Sprachen geschrieben sind ....
Jay
6
Ich schlage vor, dass Objective-c ++ keine andere Sprache ist, aber eine Mischung aus c ++ und Objective-c Unterschied ist subtil, aber es ist immer noch da
amar
1
Wie ist "nil" legal C ++? Es gibt so etwas nicht (zumindest in Standard-C ++). Bitte geben Sie ein weiteres Beispiel
rewolf
3
Aber mit ObjC können Sie einfach .mmIhre Dateien durchsuchen und (fast) fertig sein. Nicht so bei Swift.
Chakrit
6
@rewolf, ich glaube , er bedeutet eine Variable mit dem Namen nil, wieint nil
Luke
165

Die Verwirrung kann von der Annahme herrühren, dass das bloße Ändern einer Dateierweiterung von .min .mmalles ist, was Sie benötigen, um die Sprachen zu überbrücken, wenn dies in Wirklichkeit nichts dergleichen bewirkt. Es ist nicht das .mm, was Reibung verursacht .cpp, es ist der .hHeader, der definitiv kein Header sein darf C++.


Gleiches Projekt: Ja.

Im selben Projekt können Sie problemlos C , C ++ , Objective-C , Objective C ++ , Swift und sogar Assembly mischen .

  1. ...Bridging-Header.h: Sie belichten C , Objective-C und Objective-C ++ zu Swift mit dieser Brücke
  2. <ProductModuleName>-Swift.h: Setzt automatisch Ihre Swift Klassen markiert mit @objczu Objective-C
  3. .h: Dies ist der schwierige Teil, da sie für alle Varianten von C , ++ oder nicht, Objective oder nicht mehrdeutig verwendet werden . Wenn a .hkein einziges C ++ - Schlüsselwort enthält, wie z. B. class, kann es dem hinzugefügt ...Bridging-Header.hwerden und macht die entsprechende Funktion .c oder die von .cpp ihm deklarierten Funktionen verfügbar. Andernfalls muss dieser Header entweder in eine reine C- oder eine Objective-C- API eingeschlossen werden.

Gleiche Datei: Nein.

In derselben Datei können Sie nicht alle 5 mischen. In derselben Quelldatei :

  1. .swift: Sie können Swift mit nichts mischen
  2. .m: Sie können Objective-C mit C mischen . ( @Vinzzz )
  3. .mm: Sie können Objective-C mit C ++ mischen . Diese Brücke ist Objective-C ++ . ( @Vinzzz ).
  4. .c: reines C.
  5. .cpp: Sie können C ++ & Assembly ( @Vality ) mischen
  6. .h: allgegenwärtiges und mehrdeutiges C , C ++ , Objective-C oder Objective-C ++ , also hängt die Antwort davon ab.

Verweise

SwiftArchitect
quelle
1
Korrektur: In derselben .m- Quelldatei, wobei Objective-C eine strikte C-Obermenge ist, können Sie Objective-C und C ...
Vinzzz
1
Kein Problem, ich kümmere mich nicht einmal um das Guthaben, solange die Antwort die richtige ist;) Übrigens , .mm dient zum Mischen von Objective-C und C ++ (C und C ++ sind trotz des Namens zwei verschiedene Dinge )
Vinzzz
1
Ich würde erwähnen, dass C ++ im Gegensatz zu Ziel C keine C-Obermenge ist, sodass Sie nicht sowohl C als auch C ++ in einer CPP-Datei mischen können. Nur C ++ und Assembly.
Vality
1
Falls jemand feststellt, dass diese detaillierte Antwort nicht ganz hilfreich ist, wenn er versucht, Swift-Dateien in seiner Objective-C / C ++ - Datei verfügbar zu machen (Xcode beschwert sich, dass die Swift-Header-Datei nicht gefunden wird). Ich stellte fest, dass ich "ProductName / ProductModuleName-Swift.h" in meine Objective-C / C ++ - Quelldatei importieren musste . Ich fand dies etwas begraben unter: developer.apple.com/library/ios/documentation/Swift/Conceptual/…
AeroBuffalo
Guter Punkt. Ein Arbeitsprojekt zum Mischen dieser Sprachen finden Sie unter stackoverflow.com/a/32546879/218152 .
SwiftArchitect
72

Ich habe ein einfaches Xcode 6-Projekt geschrieben, das zeigt, wie man C ++ -, Objective C- und Swift-Code mischt:

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

Insbesondere ruft das Beispiel eine Objective C- und eine C ++ - Funktion aus dem Swift auf.

Der Schlüssel besteht darin, einen gemeinsamen Header Project-Bridging-Header.h zu erstellen und die Objective C-Header dort abzulegen.

Bitte laden Sie das Projekt als vollständiges Beispiel herunter.

Gian Luigi Romita
quelle
Danke für diesen Gian!
Jason Elwood
Vielen Dank für dieses Beispiel, aber wenn ich den #import "CPlusPlus.h" von ObjCtoCPlusPlus.mm in die Datei ObjCtoCPlusPlus.h verschieben möchte, gibt der Compiler den folgenden Fehler zurück: <unbekannt>: 0: Fehler: Bridging-Header konnte nicht importiert werden. /Users/Ale/Downloads/shared-master/C-ObjC-Swift/Performance_Console/Performance_Console/Performance_Console-Bridging-Header.h 'Ist es möglich, diesen Import in die Header-Datei zu verschieben?
Alessandro Pirovano
@API: Nein, du verpasst den Punkt. ObjCtoCPlusPlus.h/ `` .mm` dient ausschließlich dem Zweck, eine Ob-C-Schnittstelle für C ++ - Code bereitzustellen - es ist die Brücke, die hier eine notwendige Komponente darstellt. Lassen Sie die Includes dort, wo sie sich befinden, und fügen Sie ObjCtoCPlusPlus.…für jede C ++ - Methode, auf die Sie Zugriff benötigen , eine Methode in die Dateien ein. Sie sollten gut über sourcemaking.com/design_patterns/adapter
Slipp D. Thompson
Ich habe Ihr Beispiel heruntergeladen und es ist fantastisch für die STATIC-Funktion, die die Klasse als Beispiel anbietet, aber ich kann das Beispiel nicht für eine zusätzliche nicht statische Funktion anpassen, die von außen verwendet werden soll ... Ist das auch möglich? (Ich habe meine C ++ Hausaufgaben vor Jahrzehnten gemacht ... Ich bin momentan nicht der schärfste Bleistift der Schachtel)
Isaac
31

Sie können auch die Objective-C- Datei dazwischen überspringen . Fügen Sie einfach eine C-Header-Datei mit einer CPP-Quelldatei hinzu. Haben Sie nur C-Deklarationen in der Header-Datei und fügen Sie C ++ - Code in die Quelldatei ein. Fügen Sie dann die C-Header-Datei in die Datei ** - Bridging-Header.h ein.

Das folgende Beispiel gibt einen Zeiger auf ein C ++ - Objekt (struct Foo) zurück, damit Swift in einem COpaquePointer speichern kann, anstatt struct Foo im globalen Raum definiert zu haben.

Foo.h-Datei (von Swift gesehen - in der Bridging-Datei enthalten)

#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

Innerhalb der Quelldatei Foo.cpp (von Swift nicht gesehen):

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.
quelle
1
Diese Antwort verdient viel mehr Stimmen. Sehr nützlich.
rsp1984
Dies ist das erste Mal, dass ich gesehen habe extern "C" der Header an der Stelle verpackt wird, an der er enthalten ist, anstatt #ifdefin der Header-Datei selbst enthalten zu sein. Brillant!
dcow
27

Ich habe gerade ein kleines Beispielprojekt mit Swift, Objective-C und C ++ erstellt. Es ist eine Demo zur Verwendung von OpenCV-Stitching in iOS. Die OpenCV-API ist C ++, daher können wir nicht direkt von Swift aus mit ihr kommunizieren. Ich verwende eine kleine Wrapper-Klasse, deren Implementierungsdatei Objective-C ++ ist. Die Header- Datei ist sauberes Objective-C, sodass Swift direkt damit sprechen kann. Sie müssen darauf achten, keine indirekten C ++ - Dateien in die Header zu importieren, mit denen Swift interagiert.

Das Projekt ist hier: https://github.com/foundry/OpenCVSwiftStitch

Gießerei
quelle
Ich denke, dies beantwortet ein Problem, auf das ich heute beim Versuch gestoßen bin, eine Drittanbieter-Bibliothek KudanCV mit Swift zu verwenden. Mein Bridging-Header importiert seine .h-Datei, die Importe in <memory> <strings> und <vectors> enthält, die vermutlich aus C ++ - Bibliotheken oder -Dateien stammen. Daher wird mein Swift-Code nicht kompiliert. Ich wäre dankbar, wenn mir jemand sagen könnte, ob es einen Weg gibt, dies
Rocket Garden am
1
@RocketGarden - Die KudanCV-Headerdatei ist C ++. Sie könnten einen Wrapper schreiben, der genauso funktioniert wie meine Beispiel-Wrapper-Klasse. ODER Sie schreiben die Teile Ihrer App neu, die mit KudanCV in Objective-C ++ (mit Objective-C-Headern) kommunizieren müssen. Sie müssten nicht die Teile Ihres Projekts umschreiben, die sich nicht mit KudanCV befassen.
Gießerei
Vielen Dank dafür, ich habe es ungefähr 5 Minuten später bemerkt, aber es ist nützlich, es für andere aufzuzeichnen.
Rocket Garden
13

Hier ist mein Versuch eines Clang-Tools zur Automatisierung der C ++ / schnellen Kommunikation. Sie können C ++ - Klassen von Swift aus instanziieren, von C ++ - Klassen erben und sogar virtuelle Methoden in Swift überschreiben.
Es analysiert die C ++ - Klasse, die Sie exportieren möchten, um die Objective-C / Objective-C ++ - Brücke schnell zu generieren und automatisch zu generieren.

https://github.com/sandym/swiftpp

Sandig
quelle
8

Swift ist nicht direkt mit C ++ kompatibel. Sie können das Problem umgehen, indem Sie Ihren C ++ - Code mit Objective-C umbrechen und den Objective C-Wrapper in Swift verwenden.

Austin
quelle
Das habe ich getan. Ich schrieb einen Artikel darüber, wie man C ++ in ein schnelles Projekt integriert: learningswift.brightdigit.com/integrating-c-plus-plus-swift
leogdion
4

Nein, nicht in einer einzigen Datei.

Sie können C ++ jedoch in Swift-Projekten verwenden, ohne eine statische Bibliothek oder ein statisches Framework zu benötigen. Wie andere bereits gesagt haben, besteht der Schlüssel darin, einen Objective-C-Bridging-Header zu erstellen, der # C-kompatible C ++ - Header enthält, die als C-kompatibel mit dem externen "C" markiert sind {} Trick .

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

James Mart
quelle
2

Andere Antworten sind etwas ungenau. Sie können Swift und [Objective-] C [++] tatsächlich in derselben Datei mischen, allerdings nicht ganz so, wie Sie es erwarten würden.

Diese Datei (c.swift) wird mit swiftc c.swiftund zu einer gültigen ausführbaren Datei kompiliertclang -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;
}
// */
Schlange5
quelle
Ihr Beispielcode ist in C und nicht in C ++. Gehen Sie besser mit einem <iostream> Beispiel IMHO.
Kakyo
2

Ein Trick (von vielen) ist der

Sie benötigen einen separaten Header für Ihre Bridging-obj-c ++ - Datei ...

Sie können @interface und @implementation nicht einfach in dieselbe .mm-Datei werfen, wie dies normalerweise häufig der Fall ist.

Also in Ihrer Bridging-Header-Datei haben Sie

#import "Linkage.hpp"

Linkage.hpp hat die @ Schnittstelle für Linkage und Linkage.mm hat die @ Implementierung für .mm

Und dann

... Sie schließen "yourCpp.hpp" tatsächlich nicht in Linkage.hpp ein.

Sie geben nur #include "yourCpp.hpp"die Datei Linkage.mm ein, nicht die Datei Linkage.hpp.

In vielen Online-Beispielen / Tutorials fügt der Autor die @ Schnittstelle und die @ Implementierung einfach in dieselbe .mm-Datei ein, wie dies häufig der Fall ist.

Das wird in sehr einfachen cpp-Überbrückungsbeispielen funktionieren, aber

Das Problem ist:

Wenn Ihre yourCpp.hpp überhaupt C ++ - Funktionen hat, die sie sicherlich haben wird (wie die erste Zeile #include <something>), schlägt der Prozess fehl.

Aber wenn Sie nur nicht die haben #include "yourCpp.hpp"in der Linkage - Header - Datei (es ist in Ordnung in der .mm Datei haben, natürlich werden Sie müssen) - es funktioniert.

Auch dies ist leider nur ein Tipp im gesamten Prozess.

Fattie
quelle
1

Falls dies für jemanden hilfreich ist, habe ich auch ein kurzes Tutorial zum Aufrufen einer einfachen statischen C ++ - Bibliothek über ein triviales Swift-Befehlszeilenprogramm. Dies ist ein wirklich nackter Proof-of-Concept-Code.

Kein Objective-C beteiligt, nur Swift und C ++. Code in einer C ++ - Bibliothek wird von einem C ++ - Wrapper aufgerufen, der eine Funktion mit externer "C" -Verknüpfung implementiert. Diese Funktion wird dann im Bridging-Header referenziert und von Swift aufgerufen.

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

Anatoli P.
quelle
1

Ich stelle einen Link zu SE-0038 in der offiziellen Ressource bereit , die als Dies enthält Vorschläge für Änderungen und vom Benutzer sichtbare Verbesserungen der Swift-Programmiersprache.

Der heutige Status ist, dass dies die Funktionsanforderung ist, die akzeptiert, aber noch nicht geplant wurde.

Dieser Link soll jeden, der nach dieser Funktion sucht, in die richtige Richtung lenken

Ryan Heitner
quelle