みなさま、こんにちは。ヤフーでiOSアプリのエンジニアをしている林(@kazuhiro4949)です。
少し前になりますが、2月15日に弊社LODGEにてpotatotips #37が開催されました。
当日の様子は以下の記事で詳しくレポートされています。
- potatotips #37 (iOS/Android開発Tips共有会) 参加レポート
- potatotips#37 (iOS/Android開発Tips共有会) Androidまとめ
- 2017/2/15 #potatotips (iOS/Android開発Tips共有会) 第37回
私はヤフーからの発表者として参加し、以下の内容でLTをさせていただきました。
もともとは、IGListKitというInstagram製のUICollectionViewライブラリへ興味を持ったことがきっかけでした。IGListKitそのものはたくさんの機能を持っているのですが、その中でも特にデータソースの差分更新方法に引きつけられました。他にも同様の特徴を持ったOSSがあり、一体どういう実装なんだろうというのが出発点になっています。
この発表の中では、デモに使ったコードのライブラリ化など先の予定(願望)にも触れています。その際、参加者の方々から「実際にOSS化されたらちょっと興味あるかも」というお話をいただき、またパフォーマンスに対して懸念点もご指摘いただいたため、ちょっと時間を取ってOSSとして実装・計測してみました。
ライブラリの概要
以下の動画を見ていただくのが一番わかり易いと思います。UITableView・UICollectionViewに対して差分更新を順次行う事ができます。
UITableView | UICollectionView |
---|---|
このライブラリは、
- 更新後配列を用意する
- 更新前配列と更新後配列のdiffを取る
- diffをUIの更新処理へ変換する
というステップへ処理を形式化しています。利用者側は1.の更新後配列さえ用意すれば、後はライブラリが適切な更新処理を実行してくれるという流れになっています。
設計方針
ライブラリ化するにあたって、次のことを意識して設計しました。
- 使いたくなくなったらすぐ取り外して別のクラスと置き換えられる
- ユースケースに応じて利用者側で柔軟に拡張できる
1.は、長年iOSアプリを開発されている方であれば共感していただけるのではないでしょうか。ライブラリへロックインされた結果、メンテナンスが止まった時に大変な思いをするのを避けたいと思いました。2.は、特にUIライブラリでありがちな「そのライブラリが要件へ対応しきれない時に実装を妥協してしまう」という状況を避ける意図です。
そのため、仕様はできるだけミニマムにしつつ、標準ライブラリにも利用されている、拡張性を実現するための手法を活用しました。
以下にその一部をまとめます。現時点での全体的なクラス図(っぽいもの)はREADMEのClass Designへ載せています。
Type Erasure
標準ライブラリだとSequenceに対するAnySequenceのような構造体を指します。すごく大ざっぱに言ってしまえば、associatedtypeをもつプロトコルを変数の型としても扱えるようにするものです。
EditDistanceはdiff計算のアルゴリズムに対して拡張性を持っています。EditDistanceAlgorithmというプロトコルへ従っているものであれば自由に計算処理を差し替えられるようになっていて、Type ErasureされたAnyEditDistanceAlgorithmが存在しています。これを使うと利用者はプロトコルに従ったクラス(構造体)を用意することなく、計算アルゴリズムを差し込めるようになっています。
Proxy
これはLazySequenceで利用されている実装パターンです。OSSでは、RxSwiftがrxプロパティに利用しています。このパターンの背景としてはRxSwiftのプルリクエストが参考になるかと思います。簡単に言えば、GenericsとExtensionの型制約を使い、拡張したい型の実装をProxyオブジェクトへ委譲する、というものです。
EditDistance内だと、UIKit系クラスの拡張へ利用しています。
EditScriptConverterProxyのExtensionで、UITableViewをプロパティとして持っていたら更新のメソッドが実行できるようにしています。
計測結果
勉強会での発表中に、diff計算の速度が気になるという意見をいただきました。その時は特に調べていなかったのですが、私自身も気になっていたためAndroidのDiffUtilのようにベンチマークを測定しました。
結果はREADMEのPerformanceへ記載しています。アルゴリズムの特性上、差分が小さければ要素数はある程度増えてもそこまで重くない印象ですが、実アプリではサブスレッドで実行することを推奨します。
最後に
今回は勉強会を通じてさまざまなフィードバックをいただくことで、小さいながらもOSSの開発まで持っていくことができました。運営にかかわられた方や参加者の方々にはこの場をお借りしてお礼申し上げます。
ヤフーでは今後も社内外のエンジニア同士がコミュニケーションできる場を提供し、そこで得られた知見は積極的にそのコミュニティーへ還元していきたいと考えています。
最後にイベントの宣伝になるのですが、3月16日にヤフーが主催するiOSアプリ開発の勉強会「CAMPFIRE iOS #1」が開催されます。毎回iOSに関するあるテーマを設定し、交流することを目的としています。ご興味のある方はぜひ参加申込みをしてみてください。
こちらの記事のご感想を聞かせください。
- 学びがある
- わかりやすい
- 新しい視点
ご感想ありがとうございました