おさらい
Swiftで作成したクラスをObjective-C側で使いたい場合、Objective-Cソースで次のように宣言します。
#import "ProductModuleName-Swift.h"
// 例:#import "MyApp-Swift.h"
そうすることで、SwiftでNSObject
を継承したクラスや@objc
を付けたクラスを、Objective-Cから自由に使えるようになります。
// Swift
public class SwiftClass : NSObject { ... } // または @objc public class SwiftClass {}
public protocol SwiftProtocol { ... }
// Objective-C
#import "MyApp-Swift.h"
// ※ "Note that you cannot subclass a Swift class in Objective-C"なので注意
@interface MyClass : NSObject < SwiftProtocol >
@property (nonatomic) SwiftClass *obj;
@end
ポイントは、
- Swiftでは
NSObject
を継承するか(クラスの場合)、@objc
を付けて宣言する(クラス/プロトコルの場合) - Objective-C側で「
#import "ProductModuleName-Swift.h"
」を記述する
の2点です。Qiitaだと「Objective-CベースのプロジェクトからSwiftのクラスを呼び出す」や「SwiftとObjective-Cの相互利用する際の注意」が参考になりますね。
あと、書籍「開発のプロが教える Swift標準ガイドブック」にも当然載っています(ちょびっと宣伝)。
フレームワーク内で使いたい
それでは、このブリッジの仕組みをフレームワークを作っているときにも活用したい場合、どのように書いたらよいでしょうか?Swiftソース内の記述はよいとして、ProductModuleName-Swift.hをどうやって#import
すればいいか、という話です。
何も考えずに、ProductModuleNameにフレームワーク名(Build Settingsの[Packaging]-[Product Module Name]です)を入れてみましょう。
#import "MyFramework-Swift.h"
// → 'MyFramework-Swift.h' file not found.
はい、エラーが出てしまいました。
フレームワーク名を入れているにもかかわらず、「そのようなファイルは存在しない」と怒られています。とはいえこのファイルは自動的に生成されるファイルで、ないと言われても何かできるわけでもなく、困ってしまいますね。
この場合、次のように書けばオッケーです。
#import <ProductName/ProductModuleName-Swift.h>
// 例:#import <MyFramework/MyFramework-Swift.h>
フレームワークのProduct Module Nameだけを記述するのではなく、他のフレームワークをインポートするときと同じように、Product Name(これもBuild Settingsの[Packaging]にあります)との組み合わせで書く必要があるわけです。
まとめ
Swiftで定義・宣言したクラスやプロトコルをObjective-Cから使いたい場合、次のポイントを守れば自由に使えます。
- Swiftソースでは、NSObjectを継承するか
@objc
を付けるかして、Objective-Cに公開することを明示する - Objective-Cでは、どこで使うかによってインポートするときのパスを変える(下表)
条件 | 書き方 |
---|---|
同じアプリターゲット | #import <ProductModuleName-Swift.h> |
同じフレームワーク | #import <ProductName/ProductModuleName-Swift.h> |
今自分が見ているソースで何を作っているか、で使い分けるわけですね。
参考サイト
Appleの「Using Swift with Cocoa and Objective-C」だと、「Mix and Match」の「Swift and Objective-C in the Same Project」に載っています。