SwiftとC ++を混在させることはできますか?Objective-Cの.mmファイルのように


131

.mファイルを.mmに変更し、C ++を使用しました。Swiftで同じことをする方法はありますか?

回答:


111

いいえ。.mから.mmに切り替えると、実際にはObjective-CからObjective-C ++と呼ばれる別の言語(微妙な違いが多い)に切り替わります。つまり、実際にはC ++を使用していません。ほとんどのC ++を入力として受け入れるObjective-C ++を使用しています(C ++がすべてではないがほとんどのCを入力として受け入れるのと同じ方法で)。それが完全なC ++ではないと言うときは、nil(正当なC ++である)という名前の変数を含むC ++ファイルを検討し、それをObjective-C ++としてコンパイルしてみます。

Swiftと同じ関係はありません。CやC ++のスーパーセットではないため、.swiftファイルで直接使用することはできません。

「CocoaとObjective-CでSwiftを使用する」とは、

C ++コードをSwiftに直接インポートすることはできません。代わりに、C ++コード用のObjective-CまたはCラッパーを作成します。


93
実際にかなり面倒です-C / C ++コードベースを組み込んだCocoaアプリを使用する私たち全員が、3つの言語で書かれたプロジェクトを維持する必要があります...
Jay

6
Objective-c ++は別の言語ではないが、c ++とObjective-cの違いの混合は微妙ですが、まだそこにあることをお勧めします
amar

1
「nil」の合法的なC ++はどうですか?そのようなことはありません(少なくとも標準のc ++では)別の例を提供してください
rewolf

3
しかし、ObjCを.mm使用すると、ファイルにアクセスして(ほぼ)作業を完了できます。Swiftではそうではありません。
chakrit 2014

6
@rewolf、私は彼がのnilような変数を意味すると思いますint nil
ルーク

165

混乱は、ファイル拡張子をから.mに変更するだけで.mm言語を埋める必要があるという仮定から発生する可能性がありますが、実際には、そのようなことは何も行いません。との.mm摩擦を引き起こすの.cpp.hヘッダーではなく、ヘッダーであってはならないことC++です。


同じプロジェクト:はい。

では、同じプロジェクトで、あなたは喜んで混在させることができますCC ++Objective-Cの客観C ++スウィフトをしても、およびアセンブリ

  1. ...Bridging-Header.h:このブリッジを使用して、CObjective-C、およびObjective-C ++Swiftに公開します
  2. <ProductModuleName>-Swift.h:公開して、自動的にあなたのスウィフトの付いたクラス@objcのObjective-Cを
  3. .h:これはトリッキーな部分です。これは、C++、またはObjectiveかどうかのすべてのフレーバーにあいまいに使用されているためです。にのような.h単一のC ++キーワードが含まれていない場合は、classに追加でき...Bridging-Header.h、対応する機能.c または .cpp宣言されている機能を公開します。それ以外の場合は、そのヘッダーを純粋なCまたはObjective-C API でラップする必要があります。

同じファイル:いいえ。

同じファイル、あなたは同じで、すべての5を混在させることはできませんソースファイル

  1. .swiftSwiftと何も混在させることはできません
  2. .mObjective-CCを混在させることができます。(@Vinzzz
  3. .mmObjective-CC ++を混在させることができます。このブリッジはObjective-C ++です。(@Vinzzz)。
  4. .c:純粋なC
  5. .cppC ++アセンブリを混在させることができます(@Vality
  6. .h:ユビキタスで曖昧なCC ++Objective-CまたはObjective-C ++なので、答えはそれによって異なります。

参考文献


1
修正:同じ.mソースファイルで、Objective-Cが厳密なCスーパーセットである場合、Objective-CCを混在させることができます...
Vinzzz

1
正解ですが、問題ありません。クレジットも気にしません;)ところで、.mmは、Objective-CとC ++を混合するためのものです(名前にもかかわらず、CとC ++は2つの異なるものです) )
Vinzzz

1
目的のCとは異なり、C ++はCのスーパーセットではないため、.cppファイルでCとC ++の両方を混在させることはできません。C ++とアセンブリのみ。
Vality

1
SwiftファイルをObjective-C / C ++ファイルに公開しようとしたときに、この詳細な回答が役に立たないことが誰かにわかった場合(Xcodeは、Swiftヘッダーファイルが見つからないと不平を言っています)。Objective-C / C ++ソースファイルに「ProductName / ProductModuleName-Swift.h」インポートする必要があることがわかりました。:私はで、これはやや埋めたdeveloper.apple.com/library/ios/documentation/Swift/Conceptual/...
AeroBuffalo

いい視点ね。これらの言語が混在する作業プロジェクトについては、stackoverflow.com / a / 32546879/218152をご覧ください
SwiftArchitect 2016

72

C ++、Objective C、Swiftコードを混合する方法を示す簡単なXcode 6プロジェクトを作成しました。

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

特に、この例では、SwiftからObjective CおよびC ++関数を呼び出します。

重要なのは、共有ヘッダーProject-Bridging-Header.hを作成し、そこにObjective Cヘッダーを配置することです。

完全な例としてプロジェクトをダウンロードしてください。


このGianをありがとう!
Jason Elwood 2014

この例をありがとうございます。ただし、#import "CPlusPlus.h"をObjCtoCPlusPlus.mmからObjCtoCPlusPlus.hファイルに移動したい場合、コンパイラは次のエラーを返します:<不明>:0:エラー:ブリッジヘッダーのインポートに失敗しました ' /Users/Ale/Downloads/shared-master/C-ObjC-Swift/Performance_Console/Performance_Console/Performance_Console-Bridging-Header.h 'このインポートをヘッダーファイルに移動できますか?
アレッサンドロピロヴァーノ2014

@API:いいえ、ポイントを逃しています。 ObjCtoCPlusPlus.h/ `` .mm`は、C ++コードへのOb-Cインターフェースを提供することのみを目的として存在します。これは、ここで必要なコンポーネントであるブリッジです。インクルードはそのままにして、ObjCtoCPlusPlus.…アクセスする必要がある各C ++メソッドのファイルにメソッドを追加します。あなたは以上の読み取りにうまくやっ思いsourcemaking.com/design_patterns/adapterを
Slipp D.トンプソン

あなたの例をダウンロードしましたが、クラスが例として提供するSTATIC関数には素晴らしいですが、外部から使用される追加の非静的関数に例を適応させることができません...それも可能ですか?(私は数十年前にC ++の宿題をしました...私は今のところ箱の一番鋭い鉛筆ではありません)
Isaac

31

間にあるObjective-Cファイルをスキップすることもできます。Cヘッダーファイルと.cppソースファイルを追加するだけです。ヘッダーファイルにはC宣言のみを記述し、ソースファイルにはC ++コードを含めます。次に、Cヘッダーファイルを**-Bridging-Header.hに含めます。

次の例では、C ++オブジェクト(構造体Foo)へのポインターを返すため、Swiftは、構造体Fooをグローバルスペースで定義する代わりにCOpaquePointerに格納できます。

Foo.hファイル(Swiftから見た-ブリッジングファイルに含まれる)

#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

ソースファイルFoo.cpp内(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
この回答は値する方法よりupvotesを。本当に便利です。
rsp1984

これは、ヘッダーファイル自体ではextern "C"なく、インクルードされる場所でヘッダーをラップするのを見たのはこれが初めて#ifdefです。鮮やかさ!
dcow

27

私はSwift、Objective-C、C ++を使用して小さなサンプルプロジェクトを作成しました。これは、iOSでOpenCVスティッチングを使用する方法のデモです。OpenCV APIはC ++なので、Swiftから直接話すことはできません。私は実装ファイルがObjective-C ++である小さなラッパークラスを使用しています。ヘッダスウィフトが直接これに話すことができるように、ファイルには、Objective-Cのクリーンです。C ++風のファイルをSwiftが対話するヘッダーに間接的にインポートしないように注意する必要があります。

プロジェクトはここにあります:https : //github.com/foundry/OpenCVSwiftStitch


これは、SwiftでサードパーティのライブラリKudanCVを使用しようとして今日当たった問題に答えると思います。私のブリッジヘッダーは、C ++ライブラリまたはファイルからの<メモリ> <文字列>および<ベクトル>へのインポートを含む.hファイルをインポートします。その結果、Swiftコードはコンパイルされません。これを回避する方法があるかどうか誰かに教えてもらえれば幸いです...または、Objective-Cのすべてのコードを書き直さなければならない場合
ロケットガーデン

1
@RocketGarden-KudanCVヘッダーファイルはC ++です。私の例のラッパークラスと同じように機能するラッパーを作成できます。または、(Objective-Cヘッダーを使用して)objective-C ++でKudanCVと通信する必要があるアプリの部分を書き換えます。KudanCVに関係のないプロジェクトの部分を書き直す必要はありません。
ファウンドリ

そのおかげで、約5分後に気づきましたが、他の人のために記録しておくと便利です。
ロケットガーデン

13

C ++ / swift通信を自動化するclangツールの私の試みは次のとおりです。C ++クラスをSwiftからインスタンス化し、C ++クラスから継承し、Swiftの仮想メソッドをオーバーライドすることもできます。
エクスポートするC ++クラスを迅速に解析し、Objective-C / Objective-C ++ブリッジを自動的に生成します。

https://github.com/sandym/swiftpp




4

いいえ、単一のファイルではありません。

ただし、静的ライブラリやフレームワークを必要とせずに、SwiftプロジェクトでC ++を使用できます。他の人が言ったように、重要なのは、CとしてマークされているC互換のC ++ヘッダーを#includeするObjective-Cブリッジヘッダーを、extern "C" {}トリックと互換性のあるものにすることです。

ビデオチュートリアル:https : //www.youtube.com/watch?v=0x6JbiphNS4


2

他の答えは少し不正確です。実際には、Swiftと[Objective-] C [++]の両方を同じファイルに混在させることができますが、期待どおりにはいきません。

このファイル(c.swift)は、swiftc c.swiftclang -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;
}
// */

サンプルコードはC ++ではなくCです。<iostream>の例のIMHOを使用することをお勧めします。
kakyo

2

(多くの)1つのトリックは

ブリッジングobj-c ++ファイルには別のヘッダーが必要です...

@interfaceと@implementationを同じ.mmファイルに単にスローすることはできません。

したがって、ブリッジングヘッダーファイルには

#import "Linkage.hpp"

Linkage.hppにはLinkageの@インターフェイスがあり、Linkage.mmには.mmの@implementationがあります。

その後

...実際に、Linkage.hppに「yourCpp.hpp」を含めないでください。

#include "yourCpp.hpp"Linkage.mmファイルのみを入れ、Linkage.hppファイルは入れません

多くのオンラインの例/チュートリアルでは、ライターは@interfaceと@implementationを同じ.mmファイルに配置するだけです。

これは非常に単純なcppブリッジングの例で機能しますが、

問題は:

yourCpp.hppにc ++の機能がまったくある場合(最初の行など#include <something>)、プロセスは失敗します。

しかし、あなただけの場合はありません持って#include "yourCpp.hpp"リンケージにヘッダ(.mmファイルでそれを持っていることの罰金、明らかにあなたがする必要があります)ファイル-それは動作します。

繰り返しになりますが、これは残念ながらプロセス全体の1つのヒントにすぎません。


1

これがだれにも役立つ場合に備えて、簡単なC ++静的ライブラリを簡単なSwiftコマンドラインユーティリティから呼び出す簡単なチュートリアルもあります。これは本当に必要最低限​​の概念実証コードです。

Objective-Cは関係なく、SwiftとC ++のみです。C ++ライブラリのコードは、extern "C"リンケージを持つ関数を実装するC ++ラッパーによって呼び出されます。次に、その関数はブリッジヘッダーで参照され、Swiftから呼び出されます。

http://www.swiftprogrammer.info/swift_call_cpp.htmlを参照してください


1

SE-0038へのリンクを公式リソースに提供しています。 これは、Swiftプログラミング言語の変更とユーザーに表示される拡張機能の提案を維持するためです。

今日のステータスは、これは受け入れられたがまだスケジュールされていない機能リクエストであるということです。

このリンクは、この機能を探している人を正しい方向に導くためのものです

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.