【Swift】型推論でビルドに時間がかかっている場合の解決法

  • 8
    いいね
  • 0
    コメント
この記事は最終更新日から1年以上が経過しています。

はじめに

最近プロジェクトのビルドが遅くなってきたので、Swiftのメソッド毎のコンパイル時間を計測してビルド時間を短縮するという記事を参考にメソッド毎のビルド時間を図ってみました。

Arrayの結合

すると174536.7msというとんでもなくビルドに時間がかかっていた1つのメソッドがありました。
そこで型推論に時間がかかっていたものはこんな感じの部分でした。

//※実際のコードではなく、類似したコードを書いています

let resultDict: [String : NSObject] = ... //サーバーから受け取ったJSONがDictonaryとしてパースされたもの

//Dictionaryの中から異なるCommentListというものを取得する
guard
    let commentListA = resultDict["commentListA"] as? [[String : NSObject]],
    let commentListB = resultDict["commentListB"] as? [[String : NSObject]],
    let commentListC = resultDict["commentListC"] as? [[String : NSObject]],
    let commentListD = resultDict["commentListD"] as? [[String : NSObject]],
else { return }

//ここのArrayの結合部分で時間がかかっていた
let rawCommentList = commentListA + commentListB + commentListC + commentListD

//Comment型にDictionaryを変換(Dictionaryの中身が正しいものでない場合は、nilを返す)
let commentList = rawCommentList.flatMap { Comment(dictionary: $0) }

下記のように修正したところ、42.7msまで短縮されました。

//※実際のコードではなく、類似したコードを書いています

//Arrayを結合するメソッドを追加
extension Array {
    func join(array: [Element]) -> [Element] {
        return Array([self, array].flatten())
    }
}

let resultDict: [String : NSObject] = ...

//DictionaryのArray([[String : NSObject]])であることを明記
guard
    let commentListA: [[String : NSObject]] = resultDict["commentListA"] as? [[String : NSObject]],
    let commentListB: [[String : NSObject]] = resultDict["commentListB"] as? [[String : NSObject]],
    let commentListC: [[String : NSObject]] = resultDict["commentListC"] as? [[String : NSObject]],
    let commentListD: [[String : NSObject]] = resultDict["commentListD"] as? [[String : NSObject]],
else { return }

//"+"による結合ではなく、"join()"を使った結合に変更
let rawCommentList: [[String : NSObject]] = commentListA.join(commentListB).join(commentListC).join(commentListD)

//Comment型のArrayであることを明記
let commentList: [Comment] = rawCommentList.flatMap { Comment(dictionary: $0) }

型変換

flatMapsortを連続して行っているメソッドで、921.6msもビルドに時間がかかっていたものがありました。

//任意のCellのArrayをNSIndexPathに変換して、rowを降順にsort
let sortedIndexPaths = tableView.visibleCells.flatMap { $0 as? CustomTableViewCell }.flatMap { tableView.indexPathForCell($0) }.sort { $0.row < $1.row }

下記のように一度変数に代入してから次の処理を行うことで、136.7msまで短縮されました。
※その他の処理を行っているので、1つ目ほどの短縮とはなっていません。

//CustomTableViewCellのArrayに変換
let customCells: [CustomTableViewCell] = tableView.visibleCells.flatMap { $0 as? CustomTableViewCell }
//NSIndexPathのArrayに変換
let indexPaths: [NSIndexPath] = customCells.flatMap { tableView.indexPathForCell($0) }
//rowの降順にsort
let sortedIndexPaths: [NSIndexPath] = indexPaths.sort { $0.row < $1.row }

まとめ

Arrayを+で結合するよりもArray([[AnyObject],[AnyObject]].flatten())で結合するほうが、型推論に時間がかからないようです。
ビルド時間は短縮されましたが、Swiftらしい書き方が損なわれてしまうのが気がかりです。