ハイライト
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.shared,loadImage()直接電話してください。
(04:39) ステップ 3: C++ コードで#import "SampleApp-Swift.h"、スイフトpublic struct ImagePickerC++ で構築して使用でき、SwiftUI ビューに埋め込むこともできます。
すべての統合はコンパイラーによって自動的に行われ、呼び出しは直接かつネイティブであり、実行時の追加のオーバーヘッドはありません。
##詳細
自動的にインポートされた C++ 型
(06:15) Swift コンパイラは、標準ライブラリからのものを含む、ほとんどの C++ コレクション型を自動的にインポートできます。std::vector、std::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:22)CxxImageEngineC++ では、参照セマンティクスとともに常にポインターとして使用されます。デフォルトで 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