しめ鯖日記

swift, iPhoneアプリ開発, ruby on rails等のTipsや入門記事書いてます

CocoaPodsのライブラリをstatic化して高速化

下記事を参考にアプリ起動の高速化を試してみました。

iOSアプリの起動速度を2倍にするために、複数のDynamic FrameworkをStaticにして、ひとつのDynamic Frameworkを作る with Swift | by Muukii (Hiroshi Kimura) | Eureka Engineering | Medium

まずはDynamic Frameworkを使った時の速度を調べてみたいと思います。

まずは新規アプリを作成します。

f:id:llcc:20200909152043p:plain

作成したら起動時の設定でDYLD_PRINT_STATISTICSをYESにします。
こうする事でDynamic Frameworkのロードにどの程度時間がかかっているかも確認してみます。

f:id:llcc:20200909173908p:plain

実行結果は下の通りです。
「dylib loading time」というのがDynamicなライブラリの読み込み時間です。
3回試した所、「dylib loading time」の数字は平均で19.5msでした。

f:id:llcc:20200909220944p:plain

今回の検証はiPhone6sで試しました。
最初はシミュレータで試したのですが、ライブラリを追加しても読み込み時間にほとんど変化がなかったので実機を使うことにしました。

DYLD_PRINT_STATISTICSのログの見方は下URLを参考にしました。

[レポート] Improving Application Startup Performance #AltConf2018 #WWDC18 | Developers.IO

次はCocoaPodsを導入して変化があるかを調べます。
空のPodfileを作ってpod installをします。

platform :ios, '13.7'

target 'MyApp' do
  use_frameworks!
end

結果は下の通りです。
3回試した時の「dylib loading time」の平均は23.3msでした。
CocoaPodsなしよりは少しだけ伸びていました。

f:id:llcc:20200909221738p:plain

今度はDynamic Frameworkを複数入れてどうなるか調べてみました。
導入ライブラリは下の5つです。

platform :ios, '13.7'

target 'MyApp' do
  use_frameworks!

  pod 'SwiftDate'
  pod 'R.swift'
  pod 'RealmSwift'
  pod 'Alamofire'
  pod 'SwiftyJSON'
end

Xcodeで見るとこれらのライブラリがDynamicになっている事が分かります。

f:id:llcc:20200909153113p:plain

結果は下の通りです。
先程に比べると読み込み時間が大幅に伸びています。
3回試した時の平均読み込み時間は255.0msでした。

今回はiPhone6sですが、iPhone 11 proでも241.94msほどかかったので最新端末でも読み込み時間はかなり長いようです。

f:id:llcc:20200909222040p:plain

それと2回目の起動時は初回起動に比べると圧倒的に読み込み時間が短くなります。
おそらく2回目以降は前回の読み込みをキャッシュしているのかと思います。

端末再起動をする事で読み込み時間は再び長くなります。
アプリのプロセスの切っても長くなる時があったので、何かしらのルールでキャッシュクリアしているのだと思います。

f:id:llcc:20200909222248p:plain

次はライブラリの数を3つに減らしてみました。

platform :ios, '13.7'

target 'MyApp' do
  use_frameworks!

  pod 'SwiftDate'
  pod 'R.swift'
  pod 'RealmSwift'
end

平均は216.5msなので、ライブラリの数に応じて起動時間が変わる事が分かります。

f:id:llcc:20200909223230p:plain

Dynamic Frameworkのリンク時間の測定ができたので、次はStatic化してどうなるかを見ていきます。
CocoaPodsでStatic化するにはuse_frameworks!を外します。

target 'MyApp' do
  pod 'SwiftDate'
  pod 'R.swift'
  pod 'RealmSwift'
  pod 'Alamofire'
  pod 'SwiftyJSON'
end

普通に外すだけだと以下のようにmodule mapが必要というエラーになります。

f:id:llcc:20200910112816p:plain

上記ではRealmのmodule mapが必要というエラーだったので、Realmを追加してmodular_headers: trueオプションを付けます。

target 'MyApp' do
  pod 'SwiftDate'
  pod 'R.swift'
  pod 'Realm', modular_headers: true
  pod 'RealmSwift'
  pod 'Alamofire'
  pod 'SwiftyJSON'
end

Xcodeで見るとStatic Libraryになっている事が分かります。

f:id:llcc:20200910113054p:plain

Dynamic Frameworkの読み込み時間を調べたら平均20.1msまで減っていました。
Static化で起動時間が大きく削られた事が分かります。

f:id:llcc:20200910113318p:plain

起動画面の比較結果は下の通りです。
Staticの方が早い事が分かります。

f:id:llcc:20200910121148g:plain

use_frameworks!について

use_frameworks!はCocoaPodsのライブラリをDynamic Frameworkとして読み込む機能です。
Xcode 9まではSwiftのライブラリを静的にできなかったのでこの記述が必須でした。

参考URLは以下の通りです。

CocoaPods 1.5.0 — Swift Static Libraries - CocoaPods Blog