LoginSignup
1
0

More than 5 years have passed since last update.

SwiftとObjective-Cの間に相互互換性を保ったまま書くとコンパイル時間が異常に遅い

Last updated at Posted at 2016-12-22

前書き

最近Objective-CのプロダクトにSwiftを導入するようになりました。Swiftの移行の方針として、SwiftとObjective-Cの間に相互互換性を保ったまま移行しようという話でチームはまとまりましたが、落とし穴があったので共有しておきます。

というのもコンパイル時間が遅いのです。どうも差分ビルドがちゃんと働いていないようで、何が原因か調べてみました。

原因

ProductModuleName-Swift.h が Precompiled Header でインクルードされている

通常Objective-CからSwiftのクラスを利用しようとする場合、自動生成されるヘッダー(ProductModuleName-Swift.h)をインクルードして使用する。ちなみにこのヘッダーはSwiftで書いたクラスへのインターフェースである。

以下のようなTestClassを定義すると

class TestClass: NSObject {
    var name: String = ""
    var children = [String]()
}

自動生成されるヘッダーは以下のようになっている。

ProductModuleName-Swift.h

SWIFT_CLASS("_TtC11ProductModuleName19TestClass")
@interface TestClass : NSObject
@property (nonatomic, copy) NSString * _Nonnull name;
@property (nonatomic, copy) NSArray<NSString *> * _Nonnull children;
@end

ここからが本題だが、私が開発しているプロダクトでは便利だからという理由で、ProductModuleName-Swift.hをPrecompiled HeaderProductModuleName.pchでインクルードしてしまっていた

その結果Swiftのコードを書き換えると、Precompiled Headerに依存するファイル(つまりは全Objective-Cのファイル)を再コンパイルしだすという恐ろしい現象に陥ってしまっていた。

考察

今回の問題、例えば個別のbjective-Cの実装ファイルにインクルードするような話で済むような影響範囲だったら、あまり問題ではないのだが

Service.swift
Objective-CとSwiftを含めた多くの他クラスで使用する

class Service: NSObject {
}

SampleView.swift
一部のViewControllerのクラスで使用する

class SampleView: UIView {
}

例えば上のようなSwiftのクラスがあったとすると、このようにヘッダーファイルに書き出される。

ProductModuleName-Swift.h

SWIFT_CLASS("_TtC11ProductModuleName1Service")
@interface Service : NSObject
@end

SWIFT_CLASS("_TtC11ProductModuleName9SampleView")
@interface SampleView : UIView
@end

普通Swiftオンリーで書いていればSampleViewクラスを修正した際に、Serviceクラスには全く影響などない。しかし、同じProductModuleName-Swift.hに吐き出されるので、Serviceクラスに依存するファイルまで全て再コンパイルしてしまう。

Using Swift with Cocoa and Objective-C (Swift 3.0.1)を見ても以下のような記述が書いてあって、個別のクラスごとヘッダーをExportするような方法は書いてないし、これって解決できない問題なんですかね?

When you import Swift code into Objective-C, you rely on an Xcode-generated header file to expose those files to Objective-C. This automatically generated file is an Objective-C header that declares the Swift interfaces in your target. It can be thought of as an umbrella header for your Swift code. The name of this header is your product module name followed by adding "-Swift.h". (You’ll learn more about the product module name later, in Naming Your Product Module.)

これが今のところ解決できない問題ならば、Swiftでモデルやサービスクラスのような上位階層のクラスをSwiftで書き直してそれをObjective-Cで利用するということが難しくなってしまう

SwiftとObjective-Cに相互の互換性を保ったまま、開発することは難しいのだろうか?

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0