iOSとwatchOSのObjective-CプロジェクトでSwiftコードを動かす方法

2020年8月29日

iOSとwatchOSを含んだObjective-Cプロジェクトで、各OS共にSwiftコードを使用できるようにする方法についてです。

要点さえ抑えてしまえばとても簡単ですので是非覚えてきましょう。

1.SwiftコードをObjective-Cプロジェクトに追加する

まずObjective-Cプロジュエクトに追加します。

この時、追加するSwiftコードはNSObjectを継承したクラスでないとObjective-C側から呼び出せないことに注意が必要です。

他のクラスのSwiftコードを使用する場合は、NSObjectのSwiftクラスを独自に作り、その中で使いたいSwiftコードを呼び出すような記述が必要になります。

2.Swiftコードを呼び出したい.mファイルで"プロジェクト名-Swift.h"をimportする

次にSwfitコードを使用したいクラスの.mファイルに#import "プロジェクト名-Swift.h"の記述します。

と多くの記事がこのように書いていますが、実際はTARGETS → Build Settings → Swift Compiler - General → Objective-C Generated Interface Header Nameに設定されている~~~~.hをimportします。

例えば、TestProjectというObjective-Cプロジェクトを作成した場合のObjective-C Generated Interface Header Nameをみてみましょう。

"TestProject-Swift.h"となっていますね。

この場合「 #import "TestProject-Swift.h" 」を記述することになります。

watchOSの場合はどうなるでしょうか?

簡単です。watchOSにSwiftコードを使用したい場合も同様です。

watchOSのTARGETSの「TestProject WatchKit Extension」を選択しObjective-C Generated Interface Header Nameをみてみましょう。

"TestProject_WatchKit_Extension-Swift.h"となっていますね。

この場合は「 #import "TestProject_WatchKit_Extension-Swift.h" 」を記述することになります。

以上でObjective-CプロジェクトにSwiftコードを追加して、使用する方法の説明は終わりです。

3.サンプル

ViewController.m

#import "ViewController.h"

#import "TestProject-Swift.h"

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    
    IOSObject *object = [[IOSObject alloc] init];
    [object test];
}


- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

@end

IOSObject.swift

import UIKit

class IOSObject: NSObject {

    @objc func test() {
        print("ios object test")
    }
}

watchOSの場合は以下

InterfaceController.m

#import "TestProject_WatchKit_Extension-Swift.h"

@interface InterfaceController ()

@end


@implementation InterfaceController

- (void)awakeWithContext:(id)context {
    [super awakeWithContext:context];

    // Configure interface objects here.
    
    WOSObject *object = [[WOSObject alloc] init];
    [object test];
}

- (void)willActivate {
    // This method is called when watch view controller is about to be visible to user
    [super willActivate];
}

- (void)didDeactivate {
    // This method is called when watch view controller is no longer visible
    [super didDeactivate];
}

@end

WOSObject.swift

import UIKit

class WOSObject: NSObject {

    @objc func test() {
        print("watchos object test")
    }
}

まとめ

多くの記事がプロジェクト名-Swift.hという記載をしています。
あながち間違いじゃありませんが、スペースが_に置き換わることを知っておかないとエラーから抜け出せなくなります。

特にwatchOSを追加するとWatchKit Extensionが必ずスペース付きとなるのでハマりやすいと思いおます。