XCTextを使ってアニメーションヒッチを除去する

https://developer.apple.com/videos/play/wwdc2020/10077/

概要

アニメーションは、Appユーザの体験を劇的に向上させ、直接操作しているような感覚を与え、自身が起こしたアクションがもたらす効果をより理解することに役立ちます。
アニメーションヒッチはそのような経験を台無しにします。
スクロールやアニメーションを円滑に行うために、割り込みを検知するXCTestの使用方法について及び不具合を見つけ出す方法について。

アニメーションヒッチとは

  • ユーザが気づくアニメーションにおける乱れ
    • 1フレームが予想よりも遅れることによるアプリケーションの感性品質の低下
例えば、下記のように3Frame目がスクロールする指の動きとは異なり画面に残り続け、4Frame目で突然大きく動き指の位置に戻る

Frameの仕組み

  • iPhone/iPadのフレームは通常60Hz, 1Frame毎に16.67ミリ秒で更新する
  • iPad proでは120Hz, 1フレーム毎の更新は8.33ミリ秒
    • このような更新はVSYNCと表され、フレームの切り替え判断時に起こる
    • ヒッチが発生するのはフレームがVSYNCを逃した時
    • ヒッチの深刻度は画面上のフレームの遅れ具合で計測可能
    • 先程の例では4フレーム目が16.67ミリ秒遅れが発生している

ヒッチの確認方法

Hitch metrics

  • ヒッチタイム
    • フレームの遅延時間をミリ秒単位で表す
  • ヒッチ比率
    • 合計ヒッチタイム / 秒単位の継続時間
      • < 5 ms/s (ヒッチ率が1秒あたり5ミリ秒以下)スムーズ、UXに最適
      • 5-10 ms/s (ヒッチ率が1秒間につき5から10ミリ秒の間)ユーザが気づき検証が必要
      • > 10 ms/s (ヒッチ率が1秒あたり10ミリ秒以上)遅く、使いづらい

XCTestでのヒッチ検出

XCTextはヒッチやアニメーションデータをUnit/UI Testで取集し, MetricKitやXcode Organizerはパフォーマンスメトリクスを確認出来る MetricKitについてはWhat’s new in MetricKitを参照

XCTMetric

  • iOS11からXCTMetricを導入し、このメトリクスは計測する内容を指定する
  • テスト出来る項目
    • クロック数
    • CPU, メモリ使用率
    • os.signpost, ストレージ
  • Xcdoe12からはアプリケーションの起動時間を図るメトリクスがあり、メトリクスを測るためのテンプレートもあります
  • XCTOSSignpostMetric はアニメーションテストに使うXCTMetric
    • Xcode12で XCTOSSignpostMetric を使用するとフレームレートやフレーム数に関連するヒッチも取得可能
    • コード内でのヒッチ回数やテスト中にヒッチが継続した合計時間, ヒッチ率を追跡出来る
  • このメトリクスの収集には os.signpost interval の実行コードが必要
    • non-animation intervalは時間だけを返し、animation intervalはアニメーションメトリクスも値として返す
os_signpost(.animationBegin, log: logHandle, name: "performAnimationInterval")
os_signpost(.end, log: logHandle, name: "performAnimationInterval")
  • 定義済みのUIKitにintervalを設定することで移動やスクロールのテストが可能
extension XCTOSSignpostMetric {
     open class var navigationTransitionMetric: XCTMetric { get }
     open class var customNavigationTransitionMetric: XCTMetric { get }
     open class var scrollDecelerationMetric: XCTMetric { get }
     open class var scrollDraggingMetric: XCTMetric { get }
}

XCTestでのアニメーションパフォーマンス計測の例

タップ -> Viewを表示 -> スワイプでスクロールするUIText
ここでは XCTOSSignpostMetric.scrollDecelerationMetric によりサブメトリクスを計測する
また、Xcode12からはスクロールの速度を設定出来る
XCTMeasureOptions を使用することで計測の収集を手動で停止出来, stopMesureing をコールしアプリケーションをリセット出来る
func testScrollingAnimationPerformance() throws { 
    app.launch()
    app.staticTexts["Meal Planner"].tap()
    let foodCollection = app.collectionViews.firstMatch

    let measureOptions = XCTMeasureOptions()
    measureOptions.invocationOptions = [.manuallyStop]

    measure(metrics: [XCTOSSignpostMetric.scrollDecelerationMetric],
            options: measureOptions) {
        foodCollection.swipeUp(velocity: .fast)
        stopMeasuring()
        foodCollection.swipeDown(velocity: .fast)
    }
}

XCTestでアニメーションパフォーマンス計測する際の設定

  • perfomance計測用のtest schemeを使用
    • release buildに設定
    • debugをoff
  • UITestの設定
    • Automatic Screenshotsをoff
    • Code Coverageをoff
  • 診断用の全てオプションをoff
  • アニメーションメトリクスの設定で、Hitch Time Ratioを設定
最新情報をチェックしよう!