iOS7対応アプリでSwiftコンパイルの高速化
- 2015.12.18
- iOS
- by Hiroshi Kimura

はじめまして、Couples iOSの開発をしている木村です。
Swiftがオープンソース化され、今まで以上にSwiftへ注目が集まっていますね!
Swift × Couples iOS
Couples iOSではクラッシュの少ないアプリを提供するため、Swiftを積極的に採用しています。
Swiftが公開された当初からObjective-Cで書かれていたCouples iOSの置き換えをはじめ、言語仕様が安定しない中の開発となりましたが、今ではプロジェクト全体で6割強のソースコードがSwiftで書かれたものとなっています。

※GitHub, Language Details抜粋
積極的に採用をすすめたSwiftですが、言語仕様以外にも難点が幾つか存在しています。今回はそのうちの一つ「ビルドが遅い問題」を書こうと思います。
問題:ビルドが遅い(iOS7サポート)
Couples iOSアプリはiOS7のサポートをしているため、Module (Dynamic Library) をプロジェクトで使用することができません。
また、SwiftファイルはStatic Libraryとしてコンパイルすることも出来ないため、全てのSwiftファイルをCouples iOSプロジェクトに含めてビルドをする必要が生じてしまいます。
その影響により、Couples iOSプロジェクトをコンパイル時キャッシュオブジェクトが無い状態でビルドをすると、ビルドに要する時間が15分弱掛かってしまいます。
解決案:Module利用のターゲットを作成
ビルドに時間が掛かるのはコード量からすると仕方ありませんが、開発の時だけでも効率を上げる開発用のターゲットを用意することにしました。
- 申請用 & iOS7の開発用のターゲット
- 開発用 (iOS8, iOS9) Moduleを利用したターゲット
これにより、開発用ターゲットではビルド所要時間を最大で5分削減することに成功しました。次に対応方法を記載しておきますので、iOS7サポートを続けている開発者の方は是非参考にしてください。
1.ターゲットを複製する
まず、申請用に使用しているターゲットを複製して新しくターゲットを作成します。
「Duplicate」を選択すると、「Duplicate and Transition to iPad」(iPad用に複製しますか)と促されますが、「Duplicate Only」を選択します。
今回は新しいターゲットの名前を「Couples-moduled」としています。
2. Module用のConfigurationを作成
ターゲットごとに実行時の設定を変更するためConfigurationも複製します。
プロジェクトファイルから [Project] → [Info] を開き、下図のように [+] にてConfigurationの複製を行います。
Couples-moduledターゲットの [Build Settings] から Other Swift Flags の値に -D USE_MODULE を登録しておきます。
後ほど、Moduleのインポートを分けるための使用を説明します。
3. Podfileを複数ターゲットに対応
CocoaPodsを複数ターゲットに対応させるためPodfileを修正します。下記にサンプルを記載しておきます。
def common_pods
pod 'AFNetworking', '2.6.1'
end
target 'Couples' do
platform :ios, '7.0'
inhibit_all_warnings!
# 共通のPods
common_pods
end
target 'Couples-moduled' do
platform :ios, '8.0'
inhibit_all_warnings!
use_frameworks!
# SwiftのPods
pod 'CoreStore', git: 'https://github.com/JohnEstropia/CoreStore.git', commit: '578e4966fc87a10ebbf1bb0c4eb13e88696dc527'
pod 'GCDKit', git: 'https://github.com/JohnEstropia/GCDKit.git', tag: '1.1.4'
# 共通のPods
common_pods
end
Couples-moduled の方はフレームワークを使用する宣言をするため、use_frameworks!を呼び出しておきます。
また、Couplesプロジェクトでは一部のソースをgit-submoduleで取り込んでいるため、それらも Couples-moduled ターゲットでPodsとして取り込むようにします。
※submoduleとPodfileのバージョン(コミットハッシュ)は同一のものにしておきます
Podfile修正後はPodsを更新するためにpod installを行い、Couples-moduledターゲットにCouples-moduledで使用するxcconfigファイルを設定します。
4. ソースコードにmoduleのimportを記述
ターゲットとConfigurationの準備は整い、あとはソースコードを修正するのみです。
ソースコードは共通のため、用意した USE_MODULE フラグを利用してModuleのインポートをコンパイル時に制御します。
import UIKit
#if USE_MODULE
import SwiftyJSON
#endif
5. スキームの作成
最後にビルドするためのスキームを作成します。これも、元のスキームから [Duplicate Scheme] にて複製をし作成します。
名前を「Couples-moduled」に変更し、以下のスクリーンショットのようにConfigurationとExecutableを変更します。
- Build Configuration:Debug-moduled
- Executable: Couples-module.app
Module用ターゲットの作成はこれにて完了です。
Couples-moduledスキームでビルドを行うと、Podsに登録したライブラリはDynamic Libraryとしてコンパイルされるようになります。
まとめ
メリット
iOS7の検証時は今までどおり申請用のターゲットを使用して行う必要がありますが、開発・検証の多くはiOS8, 9に割く時間が多いと思います。
コンパイル時間を数分でも速くなれば他の作業に時間をあてることが可能になるため、ターゲットを分ける価値が存分にあります。
少し先の話になりますが、iOS7のサポートを終了した段階で Couples-moduled をそのまま申請用へとすることができるため、今後の対応を先取りすることにもなります。
デメリット
今回のターゲットを分ける懸念点は、ターゲットを申請用と開発用として分けることにより設定項目の管理が複雑化することです。
実際、Couplesプロジェクトでは xcconfig を使って設定値を共有することによりカバーしています。
以上、iOS7をサポートしているアプリでSwiftを使う場合のビルド時間短縮のTipsでした!
補足
補足1: Swiftのコンパイルについて
Swiftのコンパイルは同じModule内のクラスファイルであれば、import文が不要なのでアプリ内のクラスファイルが増加するほど依存関係を考慮する必要が生じ、1ファイルあたりのコンパイル時間が増加してしまいます。
これをModuleで細分化することによって、import文を明示的に指定し、依存関係を考慮することを減らしています。
また、Moduleのコンパイルは並列に行うことが可能なため、ビルド時間の高速化が可能となっています。
補足2: マシンスペック
開発時のマシンはMacBook Proでフルスペックです。

- 2015.12.18
- iOS
- by Hiroshi Kimura
はじめまして、Couples iOSの開発をしている木村です。
Swiftがオープンソース化され、今まで以上にSwiftへ注目が集まっていますね!
Swift × Couples iOS
Couples iOSではクラッシュの少ないアプリを提供するため、Swiftを積極的に採用しています。
Swiftが公開された当初からObjective-Cで書かれていたCouples iOSの置き換えをはじめ、言語仕様が安定しない中の開発となりましたが、今ではプロジェクト全体で6割強のソースコードがSwiftで書かれたものとなっています。
※GitHub, Language Details抜粋
積極的に採用をすすめたSwiftですが、言語仕様以外にも難点が幾つか存在しています。今回はそのうちの一つ「ビルドが遅い問題」を書こうと思います。
問題:ビルドが遅い(iOS7サポート)
Couples iOSアプリはiOS7のサポートをしているため、Module (Dynamic Library) をプロジェクトで使用することができません。
また、SwiftファイルはStatic Libraryとしてコンパイルすることも出来ないため、全てのSwiftファイルをCouples iOSプロジェクトに含めてビルドをする必要が生じてしまいます。
その影響により、Couples iOSプロジェクトをコンパイル時キャッシュオブジェクトが無い状態でビルドをすると、ビルドに要する時間が15分弱掛かってしまいます。
解決案:Module利用のターゲットを作成
ビルドに時間が掛かるのはコード量からすると仕方ありませんが、開発の時だけでも効率を上げる開発用のターゲットを用意することにしました。
- 申請用 & iOS7の開発用のターゲット
- 開発用 (iOS8, iOS9) Moduleを利用したターゲット
これにより、開発用ターゲットではビルド所要時間を最大で5分削減することに成功しました。次に対応方法を記載しておきますので、iOS7サポートを続けている開発者の方は是非参考にしてください。
1.ターゲットを複製する
まず、申請用に使用しているターゲットを複製して新しくターゲットを作成します。
「Duplicate」を選択すると、「Duplicate and Transition to iPad」(iPad用に複製しますか)と促されますが、「Duplicate Only」を選択します。
今回は新しいターゲットの名前を「Couples-moduled」としています。
2. Module用のConfigurationを作成
ターゲットごとに実行時の設定を変更するためConfigurationも複製します。
プロジェクトファイルから [Project] → [Info] を開き、下図のように [+] にてConfigurationの複製を行います。
Couples-moduledターゲットの [Build Settings] から Other Swift Flags の値に -D USE_MODULE を登録しておきます。
後ほど、Moduleのインポートを分けるための使用を説明します。
3. Podfileを複数ターゲットに対応
CocoaPodsを複数ターゲットに対応させるためPodfileを修正します。下記にサンプルを記載しておきます。
def common_pods pod 'AFNetworking', '2.6.1' end target 'Couples' do platform :ios, '7.0' inhibit_all_warnings! # 共通のPods common_pods end target 'Couples-moduled' do platform :ios, '8.0' inhibit_all_warnings! use_frameworks! # SwiftのPods pod 'CoreStore', git: 'https://github.com/JohnEstropia/CoreStore.git', commit: '578e4966fc87a10ebbf1bb0c4eb13e88696dc527' pod 'GCDKit', git: 'https://github.com/JohnEstropia/GCDKit.git', tag: '1.1.4' # 共通のPods common_pods end
Couples-moduled の方はフレームワークを使用する宣言をするため、use_frameworks!を呼び出しておきます。
また、Couplesプロジェクトでは一部のソースをgit-submoduleで取り込んでいるため、それらも Couples-moduled ターゲットでPodsとして取り込むようにします。
※submoduleとPodfileのバージョン(コミットハッシュ)は同一のものにしておきます
Podfile修正後はPodsを更新するためにpod installを行い、Couples-moduledターゲットにCouples-moduledで使用するxcconfigファイルを設定します。
4. ソースコードにmoduleのimportを記述
ターゲットとConfigurationの準備は整い、あとはソースコードを修正するのみです。
ソースコードは共通のため、用意した USE_MODULE フラグを利用してModuleのインポートをコンパイル時に制御します。
import UIKit #if USE_MODULE import SwiftyJSON #endif
5. スキームの作成
最後にビルドするためのスキームを作成します。これも、元のスキームから [Duplicate Scheme] にて複製をし作成します。
名前を「Couples-moduled」に変更し、以下のスクリーンショットのようにConfigurationとExecutableを変更します。
- Build Configuration:Debug-moduled
- Executable: Couples-module.app
Module用ターゲットの作成はこれにて完了です。
Couples-moduledスキームでビルドを行うと、Podsに登録したライブラリはDynamic Libraryとしてコンパイルされるようになります。
まとめ
メリット
iOS7の検証時は今までどおり申請用のターゲットを使用して行う必要がありますが、開発・検証の多くはiOS8, 9に割く時間が多いと思います。
コンパイル時間を数分でも速くなれば他の作業に時間をあてることが可能になるため、ターゲットを分ける価値が存分にあります。
少し先の話になりますが、iOS7のサポートを終了した段階で Couples-moduled をそのまま申請用へとすることができるため、今後の対応を先取りすることにもなります。
デメリット
今回のターゲットを分ける懸念点は、ターゲットを申請用と開発用として分けることにより設定項目の管理が複雑化することです。
実際、Couplesプロジェクトでは xcconfig を使って設定値を共有することによりカバーしています。
以上、iOS7をサポートしているアプリでSwiftを使う場合のビルド時間短縮のTipsでした!
補足
補足1: Swiftのコンパイルについて
Swiftのコンパイルは同じModule内のクラスファイルであれば、import文が不要なのでアプリ内のクラスファイルが増加するほど依存関係を考慮する必要が生じ、1ファイルあたりのコンパイル時間が増加してしまいます。
これをModuleで細分化することによって、import文を明示的に指定し、依存関係を考慮することを減らしています。
また、Moduleのコンパイルは並列に行うことが可能なため、ビルド時間の高速化が可能となっています。
補足2: マシンスペック
開発時のマシンはMacBook Proでフルスペックです。
Recommend
EvernoteのトップメニューのようなスクロールアニメーションをするCollectionViewの作り方
- 2015.12.02
- iOS
- by Shunki Tan
AWSクラウド環境でよく使うAWS CLIコマンドまとめ
- 2015.12.10
- Infra
- by Kento Yamashita