SwiftUIでSingle Source of Truthを達成するための実装方針
📄 Summarized by Claude Sonnet 4.5
SwiftUIでSingle Source of Truthを達成するための実装方針
2022年12月6日
どんなもの?
スマートバンクが開発するB/43アプリにおける、SwiftUIでSingle Source of Truthを達成して状態の不整合を防ぐための実装方針を解説した記事
WWDC 19のData Flow Through SwiftUIセッションで語られた原則を、実践的なプロフィール編集画面の実装例を通じて具体化している
ObservableObjectに準拠したViewModelによる状態管理と、単一のUIStateによる状態の一元管理を中心とした設計パターンを提示
先行研究と比べてどこがすごい?
AndroidのJetpack ComposeにおけるUIレイヤのアーキテクチャガイドと状態ホイスティングの考え方をSwiftUIに適応させている
双方向バインディングを前提とするSwiftUIにおいて、Binding.init(get:set:)を用いて単方向のデータフローを実現する実践的な方法論を提供
NavigationLink、alert、sheetなどの画面遷移要素を単一のenumで管理することで、排他的な状態管理を実現
技術や手法のキモはどこ?
UIStateという単一のenumでUI状態を表現し、関連する派生状態はcomputed propertyとして実装することで状態の重複を排除
例: isSaveButtonDisabledをUIState内のcomputed propertyとして定義し、各caseに応じた値を返す
子Viewをステートレスに保ち、Binding.init(get:set:)を使って親への単方向のイベント伝播を実現
getter: 表示する値を返す
setter: イベントを親Viewへ伝播し、ViewModelのUIStateを更新
NavigationDestinationという単一のenumで複数の遷移先を管理し、@Published private(set) var navigationDestinationで排他的に制御
alertとsheetも同様に専用のenumで一元管理し、private(set)によるアクセス制御を実現
どうやって有効だと検証した?
B/43の家計簿プリカアプリで2022年6月から新規画面に適用し、実践的な検証を実施
プロフィール編集画面という具体的なユースケースで、複数の状態管理パターン(UI状態、入力検証、画面遷移)を実装例として提示
状態の不整合が発生しやすい複数のNavigationLink管理の課題を、単一のNavigationDestinationで解決できることを実証
swiftui-navigationライブラリとの比較検討を行い、独自シンタックスの学習コストとiOS 16のNavigationStackへの移行を考慮して標準的なアプローチを選択
議論はある?
完全にJetpack Composeの設計を踏襲すると、双方向バインディングを前提とするSwiftUIでは過剰な実装になるケースが存在する
単純な画面で状態の不整合リスクが小さければ、双方向バインディングをそのまま使用する方が実用的な場合もある
「画面を描画する上で必要な状態」と「画面遷移で必要な状態」は別々に管理する方針を採用
理由: 関連しない状態を無理に統合するより、影響範囲の明文化や更新の容易性を優先
関心ごとが異なる状態は、必ずしも単一のUIStateに集約する必要はなく、別propertyへの切り出しも検討可能
NavigationLinkのList内での不安定な挙動への対策として、isActiveによる遷移管理に統一する判断
#SwiftUI
#Single_Source_of_Truth
#状態管理
#アーキテクチャ設計
#iOS開発