WWDC25:Optimize CPU performance with Instruments

Instruments を用いたCPUレベルでのパフォーマンス最適化のテクニック。バイナリサーチアルゴリズムの実装例をもとに、CPU内部の動作をマインドセットとして3ステップに分割し詳解。図解もあって直感的で、非常に見応えあったものの、後半にいくにつれ難解で理解を放棄してしまった。


0:00 – Introduction & Agenda

  • パフォーマンス予測の困難さ
    • Swift ソースコードから実際の実行環境の間に抽象化レイヤーがある
      • 機械語化されCPU実行
      • ランタイム、サポートコード、フレームワーク、カーネルも含まれ抽象化レイヤーは把握しづらい
    • CPU の並列実行、順不同(out-of-order)で実行、メモリキャッシュによる複雑性

2:28 – Performance mindset

  • オープンマインド:先入観を持たず、予想外の原因を想定、データ収集による仮説検証
  • 他の原因の考慮
    • スレッドのブロッキング(ファイルや共有状態の待機)
    • API の誤用(QoS クラス、過剰なスレッド作成)
    • 効率性の改題に対しては、アルゴリズムやデータ構造の変更を検討
    • ツール活用しボトルネックを特定(Xcode Gauges / System Trace / Hangs)
  • マイクロ最適化の注意点
    • コードの複雑化による拡張や推論の阻害や、脆弱な compiler 最適化への依存の可能性あり
  • 最適化の優先順位
    • マイクロ最適化を避けられないか検討
      • 代替手法:コード削除、遅延実行、事前計算、キャッシュ
      • これらを採用できない場合、CPUでの実行速度の向上が必要 ← 今回の主題
  • ユーザー体験に最大の影響を与えるクリティカルパスに焦点をあてて最適化すべき
    • ユーザー体験だけでなく、長時間の実行による電力消費の可能性
  • 定量化の難しい逐次的な最適化の継続により、小さな改善が大きな改善につながる
    • 継続改善のためのデータ収集用コード:
      • search クロージャを一定時間継続するまで再帰呼び出し
      • OSSignposter: 最適化対象をツールで絞り込めるようにするため、クロージャ呼び出しに使用(category: .pointsOfInterest
      • ContinuousClock: タイミング計測、Date と異なりオーバーヘッド小

8:50 – Profilers

  • Time Profiler vs CPU Profiler
    • Time Profiler:タイマーに基づきの定期的サンプリング、エイリアシング問題あり
      • エイリアシング: 定期処理がサンプリングタイマーと同じ頻度で発生、Instruments 上で結果に偏り
    • CPU Profiler:CPU クロック周波数ベース、より正確で公平な重み付けが可能
    • CPU 最適化において、CPU サイクルの最大消費箇所を特定するは CPU Profiler を利用
  • CPU Profiler の使用
    • deferred mode での低オーバーヘッド記録
    • Points of Interest での範囲設定
    • 例:Instrtuments上でコールツリーから protocol witness、allocation のオーバーヘッドを特定
      • Array の代替に Span を検討

13:20 – Span

  • Span の利点
    • Collection の代替として連続メモリ配置の要素に最適化
    • base address と count のみのシンプルな構造
    • エスケープやリークが防止され安全
  • 変更と結果:該当型を Span に変更するだけで4倍の高速化を実現
  • Span の境界チェックによるオーバーヘッドへの影響を調べる必要あり → Processor Trace

14:05 – Processor Trace

  • 革新的な機能
    • ユーザー空間で実行される全ての命令を完全にトレース(sampling bias なし)
    • 1% のみのパフォーマンス影響で無視可能
    • M4 Mac/iPad Pro、A18 iPhone での対応
  • 設定:Privacy & Security > Developer Tools での有効化
  • 使用方法
    • 数秒間の短時間トレースを推奨:記録データは数秒数GBに及ぶ可能性
    • 単一インスタンスの最適化でも十分
  • flame graph の詳細
    • 実際の実行順序通りの表示
    • 色分け
      • 茶:システム
      • マゼンダ:Swift ランタイム・標準フレームワーク
      • 青:アプリバイナリかカスタムフレームワーク
  • 発見
    • bounds check ではなく protocol metadata overhead が問題
    • 汎用的な Comparable が使用型に特化されていなかった
    • @inlinable アノテーションの追加またはInt型への手動特化の必要性
  • 結果:手動特化でコードの汎用性は失うが 1.7倍の高速化

19:51 – Bottleneck analysis

  • CPU の動作に関するメンタルモデル:2つのフェーズ
    • 命令送信(Instruction Delivery)
      • 命令がフェッチされ、マイクロ操作にデコードしCPUが実行しやすくする
    • 命令処理(Instruction Processing)
      • Map and Schedule ユニットへ送信、ルーティングとディスパッチ
      • 実行ユニット or メモリアクセス必要なら Load-Store ユニットに割り当て
    • 上記を逐次実行はフェッチ再開まで時間がかかるため、パイプライン化し並列実行
      • GCDなど複数CPUの異なるOSスレッドアクセスと異なり、1つのCPUが時間的に有利を得る
    • ユニット間でのやりとりにより、並列処理制限、パイプライン操作が停止される可能性:ボトルネック
  • ボトルネックの特定
    • CPU Counters のプリセットモード
    • 4つのカテゴリーによる CPU パフォーマンスの分析
  • 段階的な分析
    • CPU Bottlenecks レーン:Discarded bottleneck の高い割合を発見
    • Discarded Sampling セル:branch prediction miss の特定
  • CPU の命令実行の順不同性
    • 命令完了後に並べ替えるので、順番に実行したように見える(CPU による分岐予測機能)
    • 以前の実行に一貫したパターンがないと、誤った経路を辿る可能性
    • 今回はランダム性のある値比較による分岐で、予測に問題が発生した可能性
  • 変更
    • 条件付きの移動命令(conditional move instruction)を使用し、別の命令分岐を回避
    • 早期 return の除去
    • 未チェックの算術演算(unchecked arithmetic)の採用(&+)
  • 結果:2倍の高速化
  • memory hierarchy の課題
    • 予測可能なアクセスパターンでメモリアクセスすることによる高速化
    • L1、L2 キャッシュ とメインメモリへのアクセス速度差
      • L2 キャッシュは CPU 外にありヘッドルームが大幅増大
      • メインメモリは L1 キャッシュと比較し50倍低速
    • キャッシュはメモリをキャッシュラインにグループ化(64-128 bytes)
      • 4バイト要求の命令でもより多くのデータを引っ張ってくる
    • 例のバイナリサーチにおける「キャッシュミス」問題
      • 要素を並び替えてキャッシュしやすくし、検索ポイントを同じキャッシュラインに配置:エイツィンガー・レイアウト(Eytzinger layout)
  • Eytzinger layout
    • キャッシュフレンドリーな要素配置
    • breadth-first traversal によるツリー構造
    • search 速度向上と in-order traversal 速度低下のトレードオフ

31:33 – Recap

  • 全体的な成果:25倍の高速化を実現
  • 段階的なアプローチ
    1. CPU Profiler:Collection から Span への変更
    2. Processor Trace:unspecialized generics の overhead 発見
    3. Bottleneck Analysis:micro-optimization による大幅な性能向上
  • 重要な順序:software overhead の解決 → CPU bottleneck の最適化

32:13 – Next steps

  • 実践的なアプローチ
    • データ収集とパフォーマンスマインドセット
    • 繰り返し測定可能なパフォーマンステストの作成
    • Instruments の継続的な使用

WWDC25:Optimize SwiftUI performance with Instruments

Instruments を用いた SwiftUI のパフォーマンス改善。スクロール時などに発生するラグ(hangs and hitches)について、SwiftUI の描画更新ロジックを図示しながら、ケースとその因果関係を説明してくれていて、解決方法も含め非常に参考になった。シンプルな作りのアプリでも、調べてみると実は似たような状況が眠っているのではないかと思った。


0:00 – Introduction & Agenda

  • パフォーマンス問題の症状(Hitch or Hang):レスポンシブ性の低下、アニメーションの停止・ジャンプ、スクロール遅延
  • Instruments での分析:SwiftUI コードがボトルネックとなっているケースに焦点

2:19 – Discover the SwiftUI instrument

  • SwiftUI テンプレートの構成
    • SwiftUI Instrument:SwiftUI 固有のパフォーマンス問題を特定
    • Time Profiler:CPU での作業をサンプリング
    • Hangs and Hitches instruments:アプリの応答性を追跡
  • SwiftUI Instrument トラックの構造
    • 調査時はまずここのトップレベルの内容を確認する
    • Update Groups:SwiftUI が作業している時間を表示
      • ここが空いていて、Update Profiles のグラフが跳ねている場合は、SwiftUI 外が原因の可能性
    • Long View Body UpdatesViewbody プロパティが長時間実行されている場合を強調
    • Long Representable UpdatesViewViewControllerRepresentable の長時間更新を特定
    • Other Long Updates:その他の長時間 SwiftUI 更新を表示
  • 色分け:オレンジと赤で hitch や hang への寄与度を示す
    • まずは赤の更新箇所から確認することが出発点
  • 要件:Xcode 26 のインストールと最新 OS での SwiftUI traces サポート

4:20 – Diagnose and fix long view body updates

  • Command-I で リリースビルド+Instruments 起動、SwiftUI テンプレートを選択し、記録ボタンをクリック、アプリを操作
  • 問題の特定:トップレベルの 長い更新レーンを調査
    • Long View Body Updates のオレンジや赤に注目
  • Time Profiler での分析
    • View body 実行中の CPU 使用状況をコールスタックを展開して確認
    • 例:distance プロパティでの MeasurementFormatterNumberFormatter の重い処理を特定
  • レンダーループ
    • 正常な場合:イベント処理 → UI 更新 → フレーム期限前に完了 → レンダリング → 表示
    • hitch の場合:UI 更新が期限を超過 → 次のフレームが遅延 → 前フレームが長時間表示
  • パフォーマンスを高める上で、長くかかるビューの更新以外にも注意すべきこと
    • 更新が無駄に多い場合:多数の比較的高速な更新でもフレーム期限を逃す可能性

19:54 – Understand causes and effects of SwiftUI updates

  • SwiftUI の宣言的性質:UIKit のバックトレースとは異なり、SwiftUI では更新原因の特定が困難
  • AttributeGraph の動作
    • View protocol への準拠と body プロパティの実装
    • 親→子へ、属性 (attribute) を受け渡し、状態管理と依存関係の定義
      • ビュー構造体は頻繁に再作成されるが、属性がIDを維持し状態を維持する
    • state 変数変更時のトランザクション作成と期限切れのマーキング、依存関係チェーンで期限切れの更新伝播
    • 期限切れの依存関係がないものから更新を開始し、依存関係を追って逐次的に更新
  • 「なぜビュー本体が実行されたのか」→「何がビュー本体を期限切れとマークしたのか」を理解する → Cause & Effect Graph(原因と結果グラフ)
  • Cause & Effect Graph
    • 更新の原因と効果の関係をグラフで視覚化
    • 青いノード:自分のコードやユーザーアクション
    • 矢印:update や creation の関係を表示
  • ビューのデータ依存関係を細分化し、必要な箇所のみが更新されるようにするべき
    • 例:ビューがコレクションの表示する配列すべてへの依存関係を持つのではなく、ビューごとに @Observable な ViewModel を持たせる
  • Environment の考慮事項
    • EnvironmentValues 構造体への依存による更新伝播
    • 頻繁に変更される値(geometrytimer など)の environment 保存を避ける

35:01 – Next steps

  • ベストプラクティス
    • View body を高速に保つ
    • 不要な View body 更新の排除
    • データフローの設計で必要時のみ更新
    • 頻繁に変更される依存関係への注意
    • 開発中の定期的な Instruments 使用
  • 重要なポイントView body が高速かつ必要時のみに更新されることを保証する

WWDC25:Record, replay, and review: UI automation with Xcode

UIテストの自動化について。全然使いこなしていないので、結果の録画機能がここまで充実しているとは知らなかったし、失敗結果をもとに実装の修正案を提案までしてくれるとは優秀過ぎる。


0:00 – Introduction and agenda

  • Xcode の UI automation を使って、ワンクリックで複数のデバイス、言語、設定でアプリを実行
  • 全ての実行の高品質ビデオ録画を取得可能
  • テストフレームワーク:Swift Testing と XCTest の2つがある
  • XCUIAutomation:XCTest インポート時に自動で含まれ、人と同じようにアプリを自動化
  • テストの種類
    • Unit tests:アプリのロジックとモデルをテスト
    • UI automation tests:ユーザー体験、Apple ハードウェア統合、共通ワークフローをテスト

3:58 – UI automation overview

  • UI automation の利点:ジェスチャテスト、アクセシビリティ技術での知覚テスト、多言語対応確認、ハードウェア機能統合テスト、起動パフォーマンステスト
  • 3つのフェーズ:Record(操作録画)→ Replay(複数設定で再生)→ Review(ビデオと結果確認)
  • プラットフォーム対応:iOS、iPadOS、macOS、watchOS、tvOS、visionOS で同じ自動化を実行可能

6:26 – Prepare your app for automation

  • アクセシビリティとの関係:UI automation はアクセシビリティフレームワークを基盤とする
  • コード変更なく導入することが可能だが、以下手順を踏むことでテスト品質を高められる
  • accessibility identifier の追加
    • 要素を一意に識別する最良の方法
    • ローカライズされた文字列や動的コンテンツを持つ要素に追加
    • 良い identifier:アプリ全体で一意、説明的、静的
    • SwiftUI:accessibilityIdentifier modifier
    • UIKit:accessibilityIdentifier プロパティ
  • Accessibility Inspector:アクセシビリティの問題を発見・診断・修正するツール
  • UI Testing Bundle の追加:プロジェクト設定で新しい UI テストターゲットを追加

11:32 – Record your interactions

  • 録画プロセス:サイドバーのボタンで UI 録画開始、操作がコードとして自動記録
  • 録画後の作業
    • 録画されたコードのレビュー
    • XCTest API を使用した検証の追加
    • 他の automation API の探索
  • UI クエリの選択
    • ローカライズされた文字列:テキストそのものでなく、accessibility identifier を選択
    • 深くネストされたビュー:最短のクエリを選択
    • 動的コンテンツ:より汎用的なクエリ(e.g. .firstMatch)や identifier を使用
  • 検証の追加waitForExistencewait(for:toEqual:)XCTAssert などを使用
  • セットアップ最適化:orientation、appearance、location の設定、launchArgumentslaunchEnvironment の使用
    • アクセシビリティ監査の実行:.performAccessiblityAudit()

17:30 – Replay in multiple configurations

  • Test Plan の活用
    • 個別テストの包含・除外
    • システム設定の管理
    • タイムアウト、繰り返し、並列化の設定
  • 複数設定の構成
    • 各ロケールを個別の設定として追加
      • ドイツ語(長い文字列)、アラビア語・ヘブライ語(右から左のレイアウト)など長い言語のための個別構成も可能
    • 実行中ビデオ、スクショをキャプチャするか、実行後も残すか(デフォルトは失敗時のみ残す)
  • Xcode Cloud
    • クラウドでのビルド、テスト実行、App Store アップロード
    • チーム全体での実行履歴とビデオ録画の共有

20:54 – Review videos and results

  • Test Report の機能
    • 失敗したテストへのナビゲーション
    • ビデオ録画と説明の表示
    • 異なる設定での実行間の素早い切り替え
  • ビデオ解析
    • タイムライン上での失敗箇所へ直接ジャンプ
    • 失敗時点での UI 要素のオーバーレイ表示
      • 要素をクリックして、自動化コード内での推奨実装が表示
      • 複数の代替例の表示とコードの直接コピー、該当箇所に直接遷移し、ペーストして修正

WWDC25:Make your Mac app more accessible to everyone

Mac アプリのアクセシビリティ。WWDC25:Evaluate your app for Accessibility Nutrition Labels でも実演されていたように、VoiceOver 操作を実演しながら、実装による変化を説明してくれるのでとてもわかりやすい。ホバー操作のアクセシビリティは盲点だった。


0:00 – Welcome

  • アクセシビリティは誰もがアプリを体験し愛することを可能にする
  • Mac アプリ特有の特徴:キーボード・マウスインタラクション中心、密度の高い UI 、強力なマルチタスキング
  • Mac 固有の品質が重要なアクセシビリティ考慮事項をもたらす
  • 主要な要素:レイアウトの表現、ナビゲーションの加速、インタラクションのアクセシビリティ向上

0:44 – Layout

  • アクセシビリティ要素の基本概念
    • Mac アプリは多くのスペースでコントロールとコンテンツを表示
    • 視覚的なレイアウトと同様に、アクセシビリティ技術への伝達方法も重要
    • SwiftUI は個々のビューをアクセシビリティ要素として伝達、アクセシビリティ技術がアプリを理解・操作するために必要な情報
  • VoiceOver によるテスト
    • VoiceOver は様々な視覚レベルの人々がアプリを使用できるスクリーンリーダー、インターフェースを音声として聞いたり、点字として感じることが可能
    • VoiceOver でのテストはアプリのアクセシビリティをテストする優れた方法
    • Voice Control や Switch Control など他のアクセシビリティ技術との良好な体験への道
  • コンテナによるナビゲーション最適化
    • Mac では VoiceOver は主にキーボードショートカットで制御
    • 画面上の次・前の要素への移動ショートカット
    • 一度に一つの要素ずつ VoiceOver フォーカスを移動して説明を聞く
    • SwiftUI は関連アクセシビリティ要素をコンテナアクセシビリティ要素にグループ化可能
  • Mac 特有の階層構造
    • Mac では VoiceOver はデフォルトで関連要素をコンテナにグループ化、コンテナごとを移動しナビゲーションを高速化
    • Mac のアクセシビリティは iPhone や iPad とは異なり、コンテナがネストされたコンテナを含むことが多く、ツリー構造を生成
    • 入れ子のコンテナレベルが多くなりすぎないよう注意
  • .accessibilityElement(children:) modifier の活用
    • .contain: ビューをアクセシビリティコンテナとして表現、サブビューがその中のアクセシビリティ要素
    • .combine: ビューとサブビューを一つのアクセシビリティ要素として表現、すべての属性とアクションをマージ
    • .ignore: ビューを一つのアクセシビリティ要素として表現、サブビューを完全に無視
  • 要素の順序調整
    • .accessibilitySortPriority(_:) modifier を使用してアクセシビリティ要素の順序を変更
    • デフォルトのソート優先度は 0、同じ優先度のビューは視覚的位置に基づいてソート
    • 例:Book Title を Book Author より先に読み上げるため、高い優先度を設定

7:48 – Navigation

  • Rotor によるナビゲーション加速
    • VoiceOver ユーザーはすべてのページをナビゲートする必要がある
    • Rotor によりビューやテキスト範囲のコレクションを定義し、それらの間を迅速に移動可能にする
    • .accessibilityRouter(_:) modifier
  • .accessibilityDefaultFocus modifier
    • macOS と iOS 26 で、VoiceOver などのアクセシビリティ技術に初期フォーカスを提案可能
    • 新しいシーンが表示されるとき、SwiftUI はこのモディファイアを持つビューにフォーカスするよう提案

9:52 – Interaction

  • ホバーインタラクションの課題
    • ホバーによって出現する操作トリガー(ボタン)
      • VoiceOver ユーザーはポインターを動かさないためボタンにアクセス不可
    • ポインターのホバーやトラックパッドジェスチャーを必要とするインタラクションは全員にアクセシブルではない
    • .accessibilityAction(named:) modifier
      • ビューにアクセシビリティアクションを追加、VoiceOver がアクションメニューを読み上げて選択可能
    • Switch Control や Voice Control などの他のアクセシビリティ技術もこれらのアクションに依存
  • キーボードショートカットの重要性
    • アプリの一般的なタスクにキーボードショートカットを追加
    • パワーユーザー機能であるだけでなく、アクセシビリティにも大きく貢献
    • マウスを使用できない人にとって特に重要
  • カスタムコントロールの考慮事項
    • 独自のカスタムコントロールを作成する場合、他のコントロールが組み込みで持つアクセシビリティ情報を持たない可能性
    • SwiftUI Accessibility: Beyond the basics(WWDC 2021)を参照

WWDC25:Explore concurrency in SwiftUI

並行処理の基本から実践的なガイダンスまでてんこもり。@MainActor 隔離や Sendable の扱いについて、いまだにコンパイルエラーに振り回されている状況で、理解し使いこなせている感じがしないのだが、何のためにそうしたアノテーションが存在するのか、理解に近づいた気がした。


0:00 – Introduction

  • SwiftUI アプリ開発における並行処理について
  • データレースバグ(予期しないアプリ状態、ちらつくアニメーション、永続的なデータ損失)からの安全性を確保
  • SwiftUI がコードを様々な方法で並行実行する仕組みと、API の並行処理アノテーションによる識別方法を学習
  • Swift 6.2 の新しい言語モードでは、モジュール内のすべての型に @MainActor アノテーションが暗黙的に付与

2:13 – Main-actor Meadows

  • @MainActor の基本概念
    • SwiftUI の View プロトコルは @MainActor 隔離を宣言
    • e.g. ColorExtractorView が View に準拠するため、@MainActor 隔離される
      • コンパイル時に暗黙的に適用されるが実際のコードには含まれない
  • 型レベルでの隔離効果
    • 型全体が @MainActor で隔離されると、そのすべてのメンバーも暗黙的に隔離される
      • body プロパティ、@State 変数なども含む
    • 共有された @MainActor 隔離により、これらのアクセスはコンパイラによって安全であることが保証
  • コンパイル時のデフォルト
    • @MainActor は SwiftUI のコンパイル時デフォルト
    • ほとんどの場合、アプリ機能の構築に集中でき、 並行処理について考える必要がない、並行処理目的のためのコードアノテーションは不要で、自動的に安全
  • データモデルとの連携
    • データモデル型には @MainActor アノテーションが不要
    • ビュー宣言内でモデルをインスタンス化すると、Swift がモデルインスタンスの適切な隔離を保証
  • 非同期コンテキストでの利用
    • body@MainActor 隔離されているため、例では .onTapGesture で実行している Task { } クロージャもメインスレッドで実行
  • AppKit/UIKit との相互運用性
    • AppKit と UIKit の API は排他的に @MainActor 隔離
      • SwiftUI はこれらのフレームワークとシームレスに相互運用
      • UIViewRepresentable プロトコルは View プロトコルを継承し、@MainActor 隔離
      • UILabel のイニシャライザも @MainActor 隔離を要求 → @MainActor 隔離の makeUIView で機能
  • ランタイムセマンティクスの表現
    • SwiftUI の並行処理アノテーションはランタイムセマンティクスを表現
    • アノテーションはフレームワークの意図されたランタイムセマンティクスの下流

7:17 – Concurrency Cliffs

  • パフォーマンス最適化の必要性
    • アプリ機能の追加により、メインスレッドに負荷がかかりフレーム落ちやちらつきが発生
    • Task と構造化 Concurrency を使用してメインスレッドから計算処理を切り離し
  • SwiftUI の組み込みアニメーション最適化
    • 組み込みアニメーションはバックグラウンドスレッドで中間状態を計算
      • scaleEffect アニメーションの例:1から1.5の間で異なるスケール値をフレームごとに計算
      • 複雑な数学計算を含むアニメーション値の計算は高コストなため、バックグラウンドスレッドで実行
  • 宣言的特性の活用
    • SwiftUI は宣言的で、View プロトコルに準拠する構造体はメモリ内の固定位置を占有しない
    • ランタイムで SwiftUI がビュー個別の表現を作成
    • この表現により多くの最適化の機会を提供、重要なのはバックグラウンドスレッドでのビュー表現の一部評価
  • バックグラウンド実行の対象 API
    • Shape プロトコルpath メソッドがバックグラウンドスレッドから呼び出される可能性
    • visualEffect:視覚効果が高コストなため、クロージャがバックグラウンドスレッドから呼び出される可能性
    • Layout プロトコル:要求メソッドがメインスレッド外で呼び出される可能性
    • onGeometryChange:最初の引数のクロージャがバックグラウンドスレッドから呼び出される可能性
  • Sendable アノテーション
    • SwiftUI は Sendable アノテーションでコンパイラと開発者にランタイム動作を表現
    • Sendable@MainActor からデータを共有する際の潜在的なデータレースが生じる可能性があることを思い出させるもの(危険立ち入り禁止の標識のようなもの)
    • Swift はコードの潜在的なレース条件を確実に発見し、コンパイラエラーで通知
  • データレース回避戦略
    • データ競合を回避する最良の戦略は、並行タスク間でデータをまったく共有しないこと
    • SwiftUI API が sendable 関数を要求する場合、フレームワークが必要な変数の大部分を関数引数として提供
      • e.g. sizeThatFits(…) が提供する subviews パラメタ:外部変数を利用せず高度な計算が可能
  • 外部変数へのアクセス
    • sendable 関数で外部変数にアクセスする場合の制約
    • @MainActor 隔離変数を sendable クロージャで共有する一般的なシナリオ
    • self が Main actor から Background thread のコード領域に境界を越える必要がある
      • 「変数 self を バックグラウンドスレッドに送信する(Send self from main actor)」
      • この「送信」には self の型が Sendable である必要(非隔離領域での参照)
      • self のプロパティにバックグラウンドからアクセスするには、そのプロパティがどのアクターにも隔離されないことが必要(properties must be nonisolated)→ 解決方法へ
  • 問題解決方法
    • View への参照を通じたプロパティ読み取りを避ける:クロージャのキャプチャリストで変数のコピーを作成し送信 e.g. { [pulse] in ...
      • コピーを参照することで self をクロージャに送信することを回避
      • Bool などの単純な値型は sendable のため、コピーが可能
      • 関数スコープ内でのみ存在するコピーへのアクセスはデータレース問題を引き起こさない
    • 参照すべてのプロパティを非隔離状態(nonisolated)にする

16:53 – Code Camp

  • 同期 API の設計理念
    • ほとんどの SwiftUI API(Button のアクションコールバックなど)は同期的
    • 並行コードを呼び出すには、まず Task で非同期コンテキストに切り替える必要
    • Button が非同期クロージャを受け取らない理由:同期的な更新が良好なユーザー体験において重要(特に長時間のタスクの前には)
  • 長時間実行タスクでの UI 更新
    • 長時間実行タスクがあり、結果を待つ必要がある場合に特に重要
    • 非同期関数で長時間実行タスクを開始する前に、進行中であることを示すための UI 更新が重要
    • この更新は同期的であるべき、特に時間に敏感なアニメーションをトリガーする場合
  • 実例:言語モデルによる色抽出
    • withAnimation を使用して同期的に様々なローディング状態をトリガー
    • タスク完了時に別の同期状態変更でローディング状態を反転
  • フレームレートの制約
    • UI フレームワークとして、SwiftUI は滑らかなインタラクションのためにデバイスの画面リフレッシュレートの現実に対処する必要
    • スクロールなどの連続ジェスチャーに反応する際の重要なコンテキスト
  • 非同期処理とアニメーションのタイミング
    • onScrollVisibilityChange でスクロール可視性の変化を検出
    • 状態変数を true に設定してアニメーションをトリガー
    • 非同期作業前にアニメーション変更を追加する場合のタイミング問題
  • 一時停止ポイント(suspension point) の影響
    • await で非同期関数を呼ぶと一時停止ポイントが作成される
    • Task は非同期関数を引数として受け取る
    • コンパイラが await を見ると、非同期関数を2つの部分に分割
      • 最初の部分を実行後、Swift ランタイムは関数を一時停止し、CPU で他の作業を実行可能
      • この中断により、タスククロージャがデバイスのリフレッシュ期限を過ぎるまで再開されない可能性
        • → 非同期関数では不足、同期コールバックが必要
  • 同期コールバックの利点
    • SwiftUI はデフォルトで同期コールバックを提供
    • 非同期コードの意図しない中断を回避
    • 同期アクションクロージャ内での UI 更新は正しく実行しやすい
    • Task を使用して非同期コンテキストにオプトインする選択肢は常に存在
    • 同期コードが多くのアプリにとっての優れた出発点・終着点
  • UI と非 UI コードの境界分離
    • アプリが多くの並行作業を行う場合、UI コードと非 UI コードの境界を見つける
    • 非同期処理のロジックをビューロジックから分離することがベスト
      • 状態をブリッジとして使用:状態が UI コードと非同期コードを分離
    • UI ロジックはほとんど同期的に保つ
    • 非同期コードのテストが UI ロジックから独立するため、より簡単になる
  • 構造的な改善
    • 時間に敏感な変更を多く必要とする UI コードと長時間実行非同期ロジックの境界を見つけることが重要
    • ビューを同期的かつレスポンシブに保つのに役立つ
    • 非 UI コードも適切に整理することが重要

23:47 – Next steps

  • Swift 6.2 の活用
    • 優れたデフォルトアクター分離設定を提供
    • 既存アプリでの試用を推奨、ほとんどの @MainActor アノテーションを削除可能
  • Mutex の活用
    • クラスを sendable にするための重要なツール
    • 公式ドキュメントで学習方法を確認
  • 単体テストの挑戦
    • アプリの非同期コードに対する単体テストの作成
    • SwiftUI をインポートせずに実行できるかチャレンジ
  • まとめ
    • SwiftUI が Swift  Concurrency を活用して高速でデータレースフリーなアプリ構築を支援
    • SwiftUI における並行処理の確固としたメンタルモデルの獲得を目標

WWDC25:Track workouts with HealthKit on iOS and iPadOS

ワークアウトは Apple Watch で毎日使っているので、iOS / iPadOS でどういうことが可能なのか確認してみた。


0:00 – Introduction

  • 数百のヘルス・フィットネスアプリが HealthKit の暗号化されたデータベースと強力な API を活用
  • ワークアウト API は HealthKit が提供する最も強力な API の一つ
  • Apple Watch で既にワークアウトアプリを運用している場合、最小限の変更で同じコードを iPhone と iPad で使用可能

0:56 – Run a workout session

  • ワークアウトセッションの基本手順
    1. セットアップHKWorkoutConfiguration を作成し、アクティビティタイプを設定(例:ランニング、屋外)
    2. セッション作成:設定を使って HKWorkoutSession を作成
    3. ビルダー取得:ワークアウトセッションから関連する builder を取得し、データソース(HKLiveWorkoutDataSource)をアタッチ
    4. 準備session.prepare を呼び出し、3秒のカウントダウンを表示
      • オンデバイスセンサーの起動や外部心拍モニターの接続時間を確保
      • ワークアウト開始時にメトリクスがすぐに利用可能になることを保証
    5. 開始:カウントダウン完了後、セッションで startActivity、関連する workout builder で beginCollection を呼び出し
  • UI 更新の簡素化
    1. anchored object query を使用する必要なし
    2. workout builder の delegate が新しいデータ収集時に便利な更新を提供
    3. ワークアウト保存時のメトリクス同期を自動処理
  • 終了処理
    1. session.stopActivity を呼び出し、最終メトリクスの収集を許可
    2. セッションが停止状態に遷移後、builder で endCollection を呼び出し
    3. builder 完了後、セッションで end を呼び出し、ワークアウトサマリーを表示

2:50 – Get session metrics

  • 利用可能センサーの違い
    • iPhone と iPad には心拍センサーが内蔵されていない
    • 心拍 GAT プロファイル対応デバイス(ウェアラブル心拍モニター、Powerbeats Pro 2 など)とのペアリングが可能
    • ペアリング後、HealthKit が心拍データを自動取得し、Health Store にサンプルとして保存
  • データタイプの分類
    • Generated types:システムがワークアウト中に生成するデータタイプ(カロリー、距離など)
    • Collected types:ライブで観察し、ワークアウトサンプルに追加したいメトリクス
    • 例:ワークアウト中の水分摂取量を収集する場合、アプリがサンプルをヘルスデータベースに追加する必要
  • データソースの設定
    • 初期化時、データソースの types to collect プロパティには現在のアクティビティで収集可能な全サンプルタイプが含まれる
    • 外部心拍センサーがない場合でも心拍数が含まれる
    • システム生成またはアプリ保存のサンプルを観察し、live builder に渡す
  • コレクションタイプのカスタマイズ
    • enable / disable collection for type メソッドでタイプの追加・削除が可能
    • 例:ワークアウト中の水分摂取量収集時、Enable Collection を呼び出し、測定値をサンプルとしてヘルスデータベースに追加
  • 保存後のワークアウトメトリクス読み取り
    • ワークアウトオブジェクトの statistics を使用してサマリーを表示
    • 期間中のメトリクスをチャート化する場合は statistics collection query を使用
    • 細かいデータが必要な場合、HKQuantitySeriesSampleQuery を使用してより詳細なデータにアクセス
  • デバイスロック時の対応
    • iPhone はワークアウト中にロックされる可能性が高い
    • 初回ワークアウトセッション開始時、デバイスロック中でもワークアウトデータが利用可能になる旨のシステムプロンプトを表示
    • Live Activity でロックスクリーン上に重要なメトリクスを表示可能
    • プライバシー配慮:データアクセス不可時はメトリクスを省略し、ワークアウト時間のみ表示
  • Siri 対応
    • ロックスクリーンからワークアウトの開始、一時停止、再開、キャンセルが可能
    • アプリ内で Intent Handler(INExtension) を定義し、StartWorkoutIntent などの各インテントを処理
    • アプリデリゲートで Intent に応答する設定が必要

8:35 – Recover from a crash

  • クラッシュ復旧の仕組み
    • システムがクラッシュ時にアプリを自動再起動
    • ワークアウトセッションと Builder が以前の状態で復元
    • ライブデータソースの再設定が必要
  • iPhone と iPad 向けの新機能
    • 進行中のワークアウト復旧用の新しい scene delegate を追加
    • Siri インテント用に作成したアプリデリゲートにシーンデリゲートを追加してクラッシュ復旧を処理

9:34 – Best practices

  • Watch アプリ優先
    • Watch アプリがある場合、そこでワークアウトを開始して全利用可能メトリクスを取得
    • Health Store から Start Watch App を呼び出し
    • ワークアウトを iPhone にミラーリング
  • 認証リクエストの最適化
    • 必要なデータタイプのみ認証をリクエスト
    • アプリの焦点と無関係に見えるデータタイプの認証理由をユーザーが疑問に思わないよう配慮
  • Workout Builder API の使用
    • ワークアウトの作成と保存には常に workout builder API を使用
    • アクティビティリングが適切に更新されることを保証
  • 次のステップ
    • セッション添付のデモアプリ
    • 既存の iPhone/iPad アプリがある場合は Workout Builder API にアップグレード
    • Apple Watch アプリがある場合、同じ API のマルチプラットフォームサポートにより Apple Watch を持たないユーザー向けに提供可能

WWDC25:Meet WebKit for SwiftUI

とうとう WebView が SwiftUI に登場、WKWebViewUIViewRepresentable でラップして作り込んだり SFSafariViewController を使うべきか否か悩まなくて良くなるはず。JavaScript との連携や、特定位置スクロールなどもしっかりサポートされていて心強い。


0:00 – Introduction

  • WebKit は Safari, Mail、そして iOS, iPadOS, visionOS, macOS の無数のアプリの中核を担うブラウザエンジン
  • WebKit for SwiftUI の登場:全く新しい SwiftUI API により、Web コンテンツをアプリに統合することがより簡単に
  • 美しい Web コンテンツの表示が WebView を作成して URL を提供するだけで可能
  • WebKit がサポートする全プラットフォームで動作

1:54 – Load and display web content

  • WebView API の基本
    • 新しい SwiftUI ビューで Web コンテンツを簡単に表示
    • URL を提供するだけで自動的にロードして表示
    • 複数の URL の切り替えにも自動対応
      • WebView(url: toggle ? URL1 : URL2) で条件が切り替わるたびに自動的に新しい Web ビューが読み込まれる
  • WebPage クラスの活用
    • 新しい Observable クラスで Web コンテンツを表現
      • e.g. .navigationTitle(webPage.title) でタイトルを常に追従させる
    • Swift と SwiftUI と完璧に連携するよう設計
      • Web コンテンツの読み込み、コントロール、通信を行え、完全に単独で利用可能
      • WebView と組み合わせることで豊かな体験を構築
  • 多様なコンテンツロード方法
    • Loading URL requests:URLRequest を使用した load API
    • Loading HTML strings:HTML 文字列とベース URL を直接提供
    • Loading data:Web アーカイブデータ、MIME タイプ、文字エンコーディング、ベース URL を指定
  • URLSchemeHandler プロトコル
    • カスタムスキームの処理でアプリバンドル内のコンテンツやローカルファイルにアクセス
    • 独自の Scheme Handler を実装し、カスタムスキーム URL のナビゲーションを処理(e.g. lakes://
    • URLSchemeHandler プロトコルに準拠する型を作成し、reply 関数で URLSchemeTask 結果の async sequence を返す
      • URLResponse を含む URLSchemeTaskResultyield し、その後 Data を提供(同期的)
    • AsyncSequence により非同期データストリーミングも可能

9:37 – Communicate with the page

  • ナビゲーションイベントの観察
    • WebPagecurrentNavigationEvent プロパティでナビゲーション状態に簡単アクセス
    • Observable により SwiftUI と完璧に連携
  • ナビゲーションイベントタイプwebPage.currentNavigationEvent):
    • .startedProvisionalNavigation:ナビゲーション開始
    • .receivedServerRedirect:サーバーリダイレクト時
    • .committed:メインフレームのコンテンツ受信開始時
    • .finish:ナビゲーション完了時
    • .failed / .failedProvisionalNavigation:失敗時
  • Observations API との連携
    • Swift 6.2 の新しい Observations API を使用
    • currentNavigationEvent から async sequence を作成
    • for-await ループでイベント変化を観察
  • WebPage の observable なプロパティ
    • title, currentURL, estimatedProgress, themeColor など
  • JavaScript 通信
    • callJavaScript API で直接 JavaScript を評価
    • JavaScript 関数を記述し、callJavaScript で実行
    • 戻り値は optional Any なので、適切な Swift 型にキャスト
    • 引数辞書を提供可能:キーは JavaScript のローカル変数として表現
  • カスタムナビゲーションポリシー
    • WebPage.NavigationDeciding プロトコルでナビゲーションポリシーをカスタマイズ
    • ナビゲーションの異なるステップ(開始前、レスポンス受信時、認証時)でポリシー(allow / cancel)を指定
    • NavigationActionNavigationPreferences を使用してナビゲーションを制御

15:44 – Customize content interaction

  • スクロール動作のカスタマイズ
    • .scrollBounceBehavior modifier で標準的なスクロール動作を制御
    • 垂直・水平軸のバウンス動作を個別に設定可能
    • basedOnSize オプションでコンテンツサイズに基づくバウンス制御
  • visionOS での Look to Scroll
    • .webViewScrollInputBehavior modifier で Look to Scroll を設定
    • デフォルトでは無効、enabled に設定することで有効化
  • Find-In-Page サポート
    • 既存の .findNavigator modifier が WebView と完璧に連携
    • iOS/iPadOS:オンスクリーンキーボード表示時または WebView 下部に表示
    • macOS/visionOS:WebView 上部に表示
  • スクロール位置の制御
    • .webViewScrollPosition modifier でスクロール位置を WebView に関連付け
    • scrollTo を使用して特定の位置にスクロール
    • JavaScript と連携してセクション位置を計算
  • スクロールジオメトリの監視
    • .onScrollGeometryChange modifier でスクロールジオメトリの変更を監視
    • コンテンツオフセットやサイズなどの変更に対応
    • 変換関数を使用して特定の値の変更時にクロージャを実行
    • 選択されたセクションとスクロール位置の同期が可能

WWDC25:Read documents using the Vision framework

Vision フレームワークによる文書スキャンと、そのほか Vision に追加された API について。文書構造を直感的な設計で抽出できるのは嬉しい。

今回の主題ではないが、画像の美的スコアを算出する API があるとは知らなかった。このスコアリングを用いて、フリマやマッチング系などユーザー投稿画像に対する評価ができるかも?どんな画像に対してどんな結果が返るのか気になった。


0:00 – Introduction

  • Vision は機械学習を簡単にアプリに統合できる API を提供
  • 人・オブジェクト検出、身体・手のポーズ追跡、軌道解析など多様な用途に対応
  • 全ての API は完全にオンデバイス動作で、高性能かつセキュア
  • iOS, macOS, iPadOS, tvOS, visionOS で利用可能
  • 現在31種類の画像解析 API があり、今回2つの新機能を追加

1:22 – Reading documents

  • RecognizeDocumentsRequest の登場
    • 従来の RecognizeTextRequest はテキストの行を抽出するが、構造情報が失われる
    • 新しい API は文書の構造要素と重要情報を抽出可能
    • 26言語のテキスト認識に対応
    • テーブル、リスト、段落、QR コード、メールアドレス、電話番号、URL を検出
      • テーブルの場合、従来は情報構造のないテキストとテキストボックスの位置情報を突合させる必要があった
      • RecognizeDocumentRequest はテーブルごとペーストする
  • DocumentObservation の構造
    • 階層構造でテキスト、テーブル、リスト、バーコードを含むコンテナを表現
    • テーブルは2次元配列のセルで構成([[Cell]] 行・列でアクセス可能)
    • リストはアイテムで構成
    • テーブル、各要素は boundingRegion で座標情報を提供
  • 実用例:顧客登録シートの処理
    • 従来:各セルが個別オブジェクトとして返され、位置情報で行を判断
    • 新機能:テーブル構造が自動解析され、セルが行単位でグループ化
  • テキストデータの取得方法
    • transcript:コンテナ内の全テキストを単一文字列として取得
    • lines:テキストを行の配列として表示
    • paragraphsline を段落にグループ化
    • words:個別の単語リスト(中国語、日本語、韓国語、タイ語は非対応)
    • detectedData:メール、日付、URL などの重要データを自動検出
  • DataDetection フレームワークの活用
    • 電話番号、メールアドレス、郵便住所を多様な形式で検出
    • URL はリンクとして、時刻・日付はカレンダーイベントとして検出
    • 測定値と単位、金額と通貨を一緒に検出
    • 追跡番号、支払い ID、フライト番号も識別可能

13:35 – Camera lens smudge detection

  • DetectLensSmudgeRequest の導入
    • レンズの汚れにより低品質な写真が撮影されることを防ぐ
    • 汚れた画像を検出してユーザーにレンズの清掃やより良い写真の提供を促す
    • 高品質な画像のみを処理することを保証
  • 使用方法
    • smudge observation を生成し、confidence score(0〜1)で汚れの確率を示す
    • 1に近いほど汚れている可能性が高い
    • 適切な閾値(例:0.9)を設定してフィルタリング
  • 注意点と制限
    • カメラの動きによるブラー、長時間露光、雲や霧の画像も高いスコアを示す可能性
    • 低いスコアでも必ずしも高品質とは限らない
    • 他の Vision API との組み合わせ推奨:
      • DetectFaceCaptureQualityRequest:顔を含む画像の品質評価
      • CalculateImageAestheticScoresRequest:全体的な画像スコア評価(ドキュメントや領収書画像などユーティリティ画像の判別が可能)

17:59 – Hand pose update

  • 手のポーズ検出の改良
    • 2020年から DetectHandPoseRequest で21個の関節位置を検出
    • HandPoseObservation として結果を返す
    • ML 手ポーズ分類器(MLHandPoseClassifier)と手動作分類器(MLHandActionClassifier)を強化
  • 新モデルの特徴
    • より小さく現代化されたモデルに置き換え
    • 21個の関節検出は変わらず、精度向上
    • メモリ使用量とレイテンシを削減
    • 関節位置が以前のモデルと異なるため、既存の分類器の再トレーニングを推奨
  • 活用例
    • アプリ機能を制御するジェスチャ認識
    • カスタム手ポーズ・動作の分類器トレーニング

WWDC25:Code-along: Cook up a rich text experience in SwiftUI with AttributedString

AttributedString について知りたいと思ったら、TextEditor に関する内容だった。新しい TextEditor を使う機会が現状ないのと、装飾文字列を駆使する機会も今のところないが、文字列処理におけるスライスという言葉を知れて良かった。


0:00 – Introduction

  • AttributedString を使ったリッチテキスト編集体験の構築
  • TextEditorAttributedString 対応にアップグレードし、カスタムコントロールを構築、独自のテキスト書式定義を作成

1:15 – TextEditor and AttributedString

  • TextEditorAttributedString 対応
    • TextEditor(text:) に渡す @Binding var text の型を StringAttributedString に変更するだけで大幅に機能強化
      • 太字、斜体、下線、取り消し線、カスタムフォント、文字サイズ、前景色・背景色、カーニング、トラッキング、ベースラインオフセット、Genmoji をサポート
      • 加えて段落スタイリング(Line height / Text alignment / Writing direction)を新たにサポート
    • ダークモードと Dynamic Type に対応
    • システム UI による書式設定のトグル機能
  • AttributedString の基本
    • 文字列と属性の実行を含むシーケンス(属性実行)を格納
      • 属性実行の例:.largeTitle, .largtTitle + .orange
    • Swift の値型で UTF-8 エンコーディング使用
    • Equatable, Hashable, Codable, Sendable に準拠
    • カスタム属性、属性スコープの定義も可能

5:36 – Build custom controls

  • サンプルに追加機能の実装
    • 選択したテキストを材料リストに追加するボタンを作成
    • PreferenceKeyを使用してビュー階層での値の伝達
    • TextEdior$selection: AttributedTextSelection を介して選択内容を伝達
    • 単独の Range ではなく、RangeSet を使用した複数範囲の選択をサポート(双方向テキスト対応)
      • 複数言語 LtoR RtoL が混在し、跨いで選択した場合は複数の選択範囲として扱われるため
  • 双方向テキストの対応
    • 英語(左から右)とヘブライ語(右から左)のような混在テキスト
    • 視覚的な選択が複数の範囲に分割される場合に対応
    • RangeSet による不連続部分文字列のスライス機能
      • 例:.indices(where:\.isUppercase) により、すべての大文字を検出
      • text[uppercaseRanges].foreground = .blue で、大文字だけ青文字にすることが可能
  • カスタム属性の作成
    • IngredientAttribute によるテキスト範囲を材料としてマーク
    • AttributedString.Index はテキスト内のひとつの場所を表す
      • パフォーマンスのため、AttributedString ではコンテンツがツリー構造で保持、インデックスによりツリー内のパスが格納(16:25〜で図示)
      • このインデックスの動作により予想外のカーソル移動が発生してしまう
    • AttributedString indices の注意点:
      • 変更により全てのインデックスが無効化
      • 作成元の AttributedString でのみ使用可能
      • インデックスが無効になったことを検出した SwiftUI は、クラッシュ回避のためカーソルを末尾に移動する
    • AttributedString は テキストのUTF-8スカラ、UTF-16スカラへのビューが新たに得られるようになった。e.g. text.utf16[index]
    • テキスト変更時にインデックスと選択を更新
      • 範囲や範囲の配列を受け取る transform 関数による安全なインデックス更新 e.g. text.transform(updating: &cookingRange) { text in ... }
  • まとめ
    • for range in ranges のような Range のループはやめる
    • RangeSet を使った、ranges により一括でスタイル変更をする(スライス)
    • カーソル位置をテキスト変換と常に追従させるために、transform(updating:) を使用

22:02 – Define your text format

  • AttributedTextFormattingDefinition プロトコル
    • TextEditor が応答する AttributedStringKeys の定義
    • カスタムスコープでの属性制限(前景色、Genmoji、カスタム材料属性のみ許可)
    • .attributedTextFormattingDeinition(definition:) 修飾子でカスタム定義を TextEditor に渡す
    • AttributedStringKeys がスコープに含まれないものは、システム書式設定 UI に表示されない
  • AttributedTextValueConstraint プロトコル
    • AttributedTextValueConstriant.constrain(_:) で属性値の制約ロジックを実装
    • 例:材料属性がある場合は緑色、それ以外はデフォルト色
  • TextEditor による自動的な妥当性検証
    • ↑ の変更よりシステム書式設定 UI のカラーコントロールも無効になる
  • ペースト時もカスタム属性が維持される
  • カスタム属性の詳細制御
    • inheritedByAddedText:追加したテキストが属性継承をしなくなる
    • invalidationConditions:属性を削除する条件を定義(テキスト変更時など)
    • runBoundaries:属性の実行境界を制約(段落境界など)

34:08 – Next steps

  • サンプルプロジェクトの提供
    • SwiftUI の Transferable Wrapper によるドラッグ&ドロップや RTFD エクスポート
    • Swift Data を使用した AttributedString の永続化
  • AttributedString のオープンソース
    • Swift の Foundation プロジェクトの一部
    • GitHub での実装確認と貢献、Swift フォーラムでのコミュニティ交流
  • Genmoji サポート
    • 新しい TextEditor により Genmoji 入力サポートが簡単に追加可能
  • 開発のヒント
    • カスタム属性とフォーマット定義を組み合わせた高度なテキスト編集体験の構築

WWDC25:Discover Apple-Hosted Background Assets

Background Assets について。機械学習の学習済みモデルを配置するのに使えそうなのでみてみた。Apple Developer Program に付帯する 200GB の容量を使ってホスティングできるのは大きい。


0:00 – Introduction

  • アプリとアセットが人々のデバイスでどのように連携するか、Apple hosting の使用方法について説明
  • 現在利用可能なアセット配信技術(Background Assets を含む)の復習
  • iOS, iPadOS, macOS, tvOS, visionOS 向けの新機能の統合方法とローカルテスト
  • Apple hosting を使用したベータテストと App Store 配布の準備方法

1:01 – New in Background Assets

  • Background Assets により、素晴らしい初回起動体験をより簡単に提供
  • システムがデバイスでアセットをダウンロードする方法を設定し、メインアプリを更新せずに更新可能
  • 使用例:
    • 新規ダウンロード後すぐに遊べるよう、ゲームのチュートリアルレベルを提供(ゲームの残りはバックグラウンドでダウンロード)
    • In-App Purchase でアンロックするオプションのダウンロード可能コンテンツ(DLC)
    • 機械学習モデルの更新(加速された App Store への提出プロセス)
  • Asset pack の配信オプション
    • メインアプリバンドルにすべてを含める(4GB 制限、更新時はアプリ全体の再アップロードが必要)
    • URLSession
    • On-Demand Resources(一部アセット更新時でもアプリ全体の更新が必要、レガシー技術、非推奨予定)
    • Background Assets(推奨)
  • Managed Background Assets (New):システムが自動的にダウンロード、更新、圧縮などを管理
  • Apple-Hosted Background Assets
    • Apple Developer Program メンバーシップに 200GB の Apple hosting 容量が含まれる
    • 自前のサーバーにアセットをホスティングする必要なし
  • Download policies
    • Essential:アプリインストールプロセスに統合され、自動ダウンロード、インストール完了後は使用できる状態
    • Prefetch:インストール中に開始し、バックグラウンドで継続する可能性あり
    • On-demand:明示的な API 呼び出しでのみダウンロード
  • Asset pack の配信方法、バージョン管理について

7:32 – Sample app development

  • Asset pack の作成
    • macOS, Linux, Windows 用の新しいパッケージングツールを使用
    • マニフェストテンプレートを生成し、JSON ファイルで設定
    • カスタム ID、ダウンロードポリシー、サポートするプラットフォームを指定
  • Downloader extension の追加
    • Xcode で Background Download テンプレートを選択
    • Apple hosting または独自サーバーの選択
    • システム提供の完全機能付き downloader extension を使用可能
    • カスタムコードなしでアプリに追加可能
  • Asset pack の使用
    • AssetPackManager.shared.ensureLocalAvailability(of:) でローカル利用可能性を確認
    • contents(at:searchingInAssetPackWithID:options:) でファイルを読み取り
    • システムが自動的にすべての asset pack を共有名前空間にマージ
    • メモリマップされたデータインスタンスを返す(大きなアセットファイルに適している)
  • 設定
    • メインアプリと downloader extension を同じ app group に追加
    • BAAppGroupID, BAHasManagedAssetPacks, BAUsesAppleHosting キーを Info.plist に追加
  • ローカルテスト
    • macOS, Linux, Windows 用の Background Assets mock server を使用
    • SSL 証明書を発行し、テストデバイスにインストール
    • ba-serve コマンドで mock server を起動
    • Development Overrides で mock server のベース URL を設定

17:24 – Beta testing and distribution

  • Apple hosting を使用する場合
    • アプリバイナリと asset pack を App Store Connect に個別にアップロード
    • TestFlight でテスト、App Store で配布
  • Asset pack のアップロード方法
    • Transporter app:ドラッグ&ドロップ UI 体験
    • App Store Connect REST APIs:完全な制御と透明性
    • iTMSTransporter:簡素化されたコマンドラインインターフェース
  • API を使用したアップロード手順
    • backgroundAssets リソースに POST リクエストで asset pack レコードを作成
    • backgroundAssetVersions リソースに POST リクエストでバージョンレコードを作成
    • backgroundAssetUploadFiles リソースでアーカイブのアップロード予約を作成
  • TestFlight でのテスト
    • 内部テスト用に asset pack を提出
    • 外部テスト用に別途提出
    • betaBackgroundAssetReviewSubmissions リソースで API からも提出可能
  • App Store 配布
    • App Review に asset pack バージョンを提出
    • アプリバージョンと一緒に提出することも可能
    • reviewSubmissions リソースで API からも提出可能
  • 状態管理
    • Ready for Internal Testing
    • Ready for External Testing
    • Ready for Distribution
  • Webhook 通知:asset pack バージョンの準備完了時に通知を受信可能