WWDC Quick Look 💓 By SwiftGGTeam
Mix Swift and C++

Mix Swift and C++

元の動画を見る

ハイライト

Xcode 15 以降、Swift と C++ は、Objective-C ブリッジ層を必要とせず、実行時のオーバーヘッドなしで双方向インターコールを実装します。

主な内容

大規模な C++ コード ベースを維持し、画像処理エンジン、物理シミュレータ、オーディオ デコーダなど、コア ビジネス ロジックはすべて C++ で記述されています。UI 層はもともと Objective-C++ でした。 SwiftUI の新しいコンポーネントを導入したいときはいつも、最初に大量のグルー コードを作成する必要がありました。

WWDC23 以降、状況は変わりました。

Swift 5.9 では C++ 相互運用性が導入されています。C++ コード ベースで Swift ファイルを直接記述することができ、Swift コードは C++ API を直接呼び出します。逆に、C++ が Swift API を呼び出すこともできます。コンパイラは型マッピング、メモリ管理、および名前空間変換を自動的に処理するため、手書きのブリッジング ヘッダーの必要がなくなります。

(02:21) 講演者は、画像処理フレームワークには C++、UI には Objective-C++ という写真編集アプリをデモンストレーションしました。彼女は SwiftUI の PhotoPicker を追加したいと考えています。以前は、Objective-C ブリッジング レイヤーを作成する必要がありました。これで、プロジェクト内に新しい Swift ファイルを直接作成できるようになりました。

双方向通話の実際のプロセス

(02:47) ステップ 1: ビルド設定で、「Swift コンパイラー - 言語」の「C および Objective-C 相互運用モード」を「C および Objective-C」から「C++ および Objective-C++」に変更します。

(03:16) ステップ 2: Swift ファイル内import CxxImageKitでは、C++ フレームワークの API が Swift スタイルで表示されます。CxxImageEngine::sharedなるCxxImageEngine.sharedloadImage()直接電話してください。

(04:39) ステップ 3: C++ コードで#import "SampleApp-Swift.h"、スイフトpublic struct ImagePickerC++ で構築して使用でき、SwiftUI ビューに埋め込むこともできます。

すべての統合はコンパイラーによって自動的に行われ、呼び出しは直接かつネイティブであり、実行時の追加のオーバーヘッドはありません。

##詳細

自動的にインポートされた C++ 型

(06:15) Swift コンパイラは、標準ライブラリからのものを含む、ほとんどの C++ コレクション型を自動的にインポートできます。std::vectorstd::map待って。C++ 型はデフォルトで Swift の構造体 (値型) にマッピングされ、演算子は対応する Swift 演算子にマッピングされ、コンテナは自動的に Swift の構造に従います。Collectionプロトコル。

// C++ 的 std::vector<Image*> 在 Swift 中可直接遍历
for image in CxxImageEngine.shared.pointee.getImages() {
    let uiImage = CxxImageEngine.shared.pointee.uiImageFrom(image)
    UIImageWriteToSavedPhotosAlbum(uiImage, nil, nil, nil)
}

キーポイント:

  • getImages()C++ に戻るstd::vector, Swift は、それを走査可能なコレクションとして自動的に認識します。
  • for...inベクトルには次のような特徴があるため、ループは直接利用できます。begin()そしてend()方法
  • コンパイラは、トラバース時の安全性を確保し、C++ イテレータの一般的なライフサイクルの問題を回避します。

アノテーションを使用して API インポートを最適化する

(07:44) コンパイラーによって自動的にインポートされた API は、十分に「Swift らしく」ない場合があります。合格swift/bridgingヘッダー ファイル内の注釈により、インポート動作を細かく制御できます。

SWIFT_SHARED_REFERENCE: C++ 型を Swift クラスにマップします

08:22CxxImageEngineC++ では、参照セマンティクスとともに常にポインターとして使用されます。デフォルトで Swift 構造体としてインポートされる場合、各アクセスを記述する必要があります.pointee、タイプは次のように表示されます。UnsafePointer

C++ ヘッダー ファイルに注釈を追加します。

#import <swift/bridging>

struct SWIFT_SHARED_REFERENCE(IKRetain, IKRelease) CxxImageEngine {
    static CxxImageEngine *shared;
    void loadImage(UIImage *image);
    std::vector<Image *> getImages() const;
    UIImage *uiImageFrom(Image *image) const;
};

キーポイント:

  • SWIFT_SHARED_REFERENCE(retainFunc, releaseFunc)これが参照型であることを Swift に伝えます
  • Swift はライフサイクルを自動的に管理し、指定されたIKRetainそしてIKRelease関数
  • インポート後、Swift で直接使用しますCxxImageEngine.shared、もう必要ありません.pointee

SWIFT_COMPUTED_PROPERTY: ゲッター/セッターを計算されたプロパティとしてマップします

(08:22) C++ で一般的なgetImages() / setImages()Swift ではネーミングが十分自然ではありません。

/// \returns all images that have been loaded into the engine.
SWIFT_COMPUTED_PROPERTY
inline std::vector<Image *_Nonnull> getImages() const;

キーポイント:

  • SWIFT_COMPUTED_PROPERTYgetter メソッドに注釈を付ける
  • Swift で自動的にマッピングされます。images財産
  • メソッドの呼び出し元engine.getImages()なるengine.images

更新された Swift コード:

for image in CxxImageEngine.shared.images {
    let uiImage = CxxImageEngine.shared.uiImageFrom(image)
    UIImageWriteToSavedPhotosAlbum(uiImage, nil, nil, nil)
}

その他の一般的な注釈

08:42

// 标注返回值是独立值,Swift 不会隐式保留引用
SWIFT_RETURNS_INDEPENDENT_VALUE
std::string_view networkName() const;

キーポイント:

  • SWIFT_RETURNS_INDEPENDENT_VALUE一時的な値またはビューの型を返す関数
  • 呼び出し元が戻り値を独立して保持し、ダングリング参照を避ける必要があることを Swift に伝えます。

C++ から Swift を呼び出す

(04:45) としてマークされた Swift コードpublicその後、コンパイラは C++ で使用するヘッダー ファイルを生成します。

#import "SampleApp-Swift.h"

- (IBAction)openPhotoLibrary:(UIButton *)sender {
    // 构造 SwiftUI 视图并在 C++ 中调用
    SampleApp::ImagePicker::init().present(self);
}

キーポイント:

  • #import "ProjectName-Swift.h"生成されたヘッダー ファイルをインポートする
  • スイフトpublic structC++ で名前空間として公開される
  • SwiftUI ビュー、メソッド呼び出し、プロパティ アクセスをサポート

重要ポイント

1. C++ コードベースの Swift への段階的な移行

  • やるべきこと: 既存の C++ プロジェクトに Swift モジュールを段階的に導入し、UI レイヤーまたはビジネス レイヤーを置き換えます。
  • 価値がある理由: コア C++ エンジンを書き直すことなく、SwiftUI や Swift Concurrency などの最新の機能を使用できます。
  • 開始方法: 新しい Swift ファイルを作成し、ビルド設定で C++ 相互運用性をオンにし、直接importC++ フレームワーク

2. Swift で使用できるように C++ ゲーム エンジンをカプセル化

  • 内容: アノテーションを使用して C++ ゲーム/レンダリング エンジンのコア インターフェイスを最適化し、Swift に公開します。
  • 実行する価値がある理由: ゲーム ロジックはパフォーマンスを確保するために C++ を使用し、UI とレベル エディターは SwiftUI を使用して迅速に開発されます。
  • 開始方法: を使用しますSWIFT_SHARED_REFERENCEエンジンのシングルトンのライフサイクルを管理するには、次を使用します。SWIFT_COMPUTED_PROPERTY属性アクセスを最適化する

3.クロスプラットフォーム C++ ライブラリ + Swift フロントエンド

  • やるべきこと: 同じ C++ コア ライブラリ。iOS では SwiftUI を使用し、Android では Kotlin を使用します。
  • 実行する価値がある理由: C++ の相互運用性は Linux と Windows をサポートしており、コア コードは完全に再利用可能です
  • 開始方法: C++ ライブラリをフレームワークにコンパイルすると、Swift プロジェクトは追加のバインディング レイヤーなしでそれに直接依存します。

4.機械学習モデルの推論層の最適化

  • 内容: Swift 経由で呼び出される Core ML 外部のカスタム C++ 推論コード (ONNX ランタイムなど)
  • 実行する価値がある理由: Objective-C++ ブリッジングの複雑さを回避し、Swift で入力テンソルと出力テンソルを直接管理します。
  • 開始方法: C++ 推論エンジンをフレームワークとしてカプセル化し、Swift で画像/テキストの前処理を処理し、推論のために C++ API を呼び出します。

関連セッション

  • Swift の新機能 — Swift 5.9 の新機能の概要と、C++ の相互運用性の完全なコンテキスト
  • Swift マクロの作成 — Swift 5.9 言語の改善に伴う Swift マクロ システム
  • Xcode 15 の新機能 — Xcode 15 で C++ 相互運用性を有効にするための完全なセットアップ プロセス
  • SwiftData について — 移行された Swift レイヤーでデータの永続性が必要な場合、SwiftData がネイティブ ソリューションになります。

コメント

GitHub Issues · utterances