ストリーミングはほとんどのブラウザと
Developerアプリで視聴できます。
-
SwiftUIのデータフロー
SwiftUIは、矛盾のない、美しく正確なユーザーインターフェイスを記述できるよう、ゼロから構築されています。このセッションでは、UIを完全に予測可能でエラーフリーにしながら、データの依存関係をつなぐ方法を紹介します。SwiftUIの強力なデータフローツールと、各状況における最適なツールについてご確認ください。
リソース
関連ビデオ
WWDC19
-
ダウンロード
(音楽)
(拍手) おはようございます
今回はSwiftUIのお話です 私はルカ・ベルナルディ 後で友人のラジも来ます SwiftUIにワクワクしますか? (喝采) どうも (拍手) この日を 楽しみにしていました SwiftUIは アプリケーション作成手段の近道 しかし我々はUI開発を より簡単にするため― ゼロから デザインし直しています データはSwiftUIの 第1級オブジェクトです
今回はView Hierarchyに データを流し込める― シンプルでパワフルな ツールを紹介します 美しいだけでなく使いやすい アプリケーションを作れます
View Hierarchyがどう変わったかも 見てみましょう 正しく矛盾のないデータ表示を 保証します
最後に誰でも入手可能なツールで データの理解を助けます
話を進める前に データとは何でしょう? データとは UIを動かす情報です あらゆる形と形式をとります 例えばUIにToggleのような Stateを与えるなどです モデルデータもデータです メッセージリストを動かす オブジェクトのようにです
我々にはあなたを手助けする ツールがあります すでにいくつかご存じですね 詳しく知らなくても大丈夫 これから使い方を説明します この話が終わるころには 理解しているでしょう
ツールを紹介する前に 二つの基本理念を説明します
一つはデータを読み込む度に 依存性を構築していること データに合わせ新しい値が示される これが依存性です
青い方はプレイバック制御を 示しています 紫のビューのデータを読み込みます 値が変わる度にビューを 更新する必要があります
これは手動で行われるため 作業が複雑になります
SwiftUIの データの依存性は宣言的です 手動の同期や無効化は 不要となります
単にデータの依存性を― フレームワークに 書くだけでいいのです
ベストなユーザ体験の 構築に集中できます
二つ目はすべてのデータは 単一データソースを持つこと
それはView Hierarchyの 中にあります 折り畳みや展開の Stateがある時や― 永続性モデルからの通知を 表示している時―
データソースの場所に関わらず それを見ることができます
データソースの複製は バグや矛盾を生みます 常に同期させる必要が あるからです 同じデータを何度も 複製するわけです 二つのビューの使用や― 通知の受け取り イベントの連続などの― 複雑さがバグを引き起こします 失敗して当然です 同じ間違いを 何度も犯してきました
そこでデータを共通祖先まで 引き上げ― 二つの子要素に参照させます
データソースがビューとデータ間の バグを排除します 言語内で宣言することで 使用できます
これを踏まえると あなたは コード中のデータソースを見て― データを構築する際の 意思決定に使えます
通勤時に私はよく Podcastを聞きます SwiftUIはそのプレーヤーの 構築に適しています
このお話の中ですべての ツールの実演を行います このUIを制作します インターフェイスに タイトル 再生ボタン― 現在時刻を表示します
段階的に 構築していきましょう まずはタイトルの表示からです
これはプレーヤービュー 再生中のエピソードを 保存できます
タイトルも表示したいですね テキストを垂直方向に重ねる VStackも作ります
もちろん従来の Swiftプロパティも使います すべてのデータの 引き出し経路を見られます 親からビューに 与えられるデータです
再生と停止についても 見ていきましょう
再生中かどうかを 示すプロパティです 値によって異なるクリップが 再生されます
しかし再生ボタンは インタラクティブにしたいです タップすると再生状態になり 画像も切り替わります
ボタンを使って それができます
ボタンはタップ時に アクションを起こします isPlayingを切り替えます
コンパイルエラーが 出ますが― これにより 正しい経路へと導かれます View Hierarchyは 操作しません
UIが更新される度に 異なる値を生み出します こういったケースには Stateを用います
見てみましょう
Property Wrapperを isPlayingに用います 時間変化する値をシステムに 伝えることができます プレーヤービューは それに従います
今度はエラーが出ません ボタンをタップすると―
値が変化し 新しいbodyが生まれます このProperty Wrapperは― Swift 5.1の すばらしい特徴です
挙動の詳細までは 立ち入りません 気になる方は この二つのセッションをどうぞ
Property Wrapperを 導入すると― プロパティを増強できる これだけ覚えてください
どう機能するのか? そう思うかもしれません
変数にはビュー上で 容量が割り当てられ― 追跡ができます
システムが動的に容量を作れば 初期値を指定する必要があります
ビューは頻繁に更新されますが ストレージは保持されます 複数の更新があってもです
プロパティには明確に プライベートと示され― Stateはビューによって 管理されます
ボタンをタップしたときに 何が起きるか見てみましょう
これはView Hierarchy Stateを定義すると― ストレージが割り振られます Stateの変数が変わると SwiftUIが動き出します
SwiftUIはStateの変数が bodyを構築し ビューをレンダリングすると 理解しています
ボタンでアクションを実行し Stateを切り替えます
Stateが変化すると ビューを有効にします
bodyとその子要素を 再計算するのです
すべての変化は 下に流れていきます この操作は 効率よく行われます 変化した部分だけを レンダリングするからです
フレームワークが依存性を 管理してくれるのです
ここでデータソースの話に 戻りましょう Stateを宣言する度に― ビューが持つ新たな データソースを定義します ここに示していることは とても重要です
もう一つ重要なのはビューは Stateの機能であることです
今まではView Hierarchyを 直接 操作してきました サブビューをつけ足したり 変数を変えたりです SwiftUIでは Stateを操作し Stateはデータソースとして働きます
宣言的シンタックスの 美点です ビューには現在のStateが 表示されます UI構築の複雑さを取り扱う 助けとなります 美しく正常な インターフェイスを作れます
次はユーザからの フィードバックについてです
ユーザから始めましょう
ユーザは アプリケーションを使います
アクションが実行され Stateが切り替わります
Stateの変化を検出すると ビューも更新してくれます
更新されたUIをユーザは 使うことができます
このモデルではデータは 常に一方向に流れます 最終点というものが ありません ビューの更新は予想しやすく 理解が容易になります
アプリケーション構築にも 改善を施しました
ポーズをタップしたら タイトルをグレーにしたいです isPlayingを使って 色を選べばよいですね
次はリファクタリングのお話です SwiftUIにとってビューは 大した重荷にはなりません データがより小さな 再利用可能な要素に― グループ分けされる心配は なくなります ここによい例があります
再生と停止ボタンのコードです
これをビューに カプセル化し― PlayButtonと呼びましょう
では実行してみます
新しいビューに入っただけで 同じコードです 新たにStateを作るのは 得策ではありません Stateを使うとisPlayingの データソースが一つ増えます PlayerViewのStateと 同期する必要があります 面倒ですよね
もっと便利にしたいです ビューにはデータソースを持たせず 読み込みと切り替えに使います
Stateも持たせません そのためのツールが Bindingです
Binding Property Wrapperを使えば データソースを持たずに 依存性を定義できます
初期値を指定する必要もありません Stateから引き出されます 例を見てみましょう
変更点はBindingの使用と 初期値の省略です 単純ですね
PlayButtonにBindingが 付与される様子です
PlayerViewはStateを 保持し続けています
プロパティ名に“$”を付けて Bindingを引き出せます
要素がBindingを通じて Stateにアクセスできます
$接頭辞も Property Wrapperの特徴です 詳しくは“Modern SwiftAPI Design”をご覧ください
このシンプルさと パワフルさを感じてください PlayButtonはisPlayingの 値のコピーを含みません Bindingを通じて 参照するので― ビューにデータを 同期する必要はありません
UIKitで書く場合と 比較してみましょう
複数のビューがユーザ操作に 対応しなければなりません 手動設定か デリゲートの定義が必要です モデルの変化を観測し 対応する必要があります 値が変化する度に必要箇所を 設定し直さなければなりません
アプリケーションの複雑さは 問題を生みます それは皆さんもご存じですね View Controllerは データをビューと同期します こういった複雑さが SwiftUIにはありません
簡単にデータ依存性を 定義でき― あとはフレームワークで 済みます View Controllerは もう要りません (拍手と喝采) これはフレームワーク全体に 適用されます
ToggleやTextFieldなど APIにも使えます あなたはデータソースを 管理し続けます
データを作成し要素に与え― 複製や手動の同期なしに 参照できます すばらしいことです
SwiftUIにおいてビューは― レイアウトから ナビゲーションまで示します 実はそれだけではありません プレゼンテーション論理の カプセル化にも便利です フレームワークは 構成要素を― 小さなビューで示す 手助けをしてくれます
小さなユニットの構成へ導き 理解を容易にします
例に戻ります
デザイナーに見せると コードの短さに驚きましたが
改善点の指摘もありました “状態の移行を 動画にすべきだ”と
幸いそれは簡単なことでした すべての変更が 保存されるからです アニメーションは Stateで簡単かつパワフルにできます
アニメーションブロックに Bindingを使うと― 値の変化に応じて アニメーションが動きます アニメーションはいつも 正常に動作します
アニメーションについて もっと知りたい方は “Building Custom View in SwiftUI”をご覧ください
StateとBindingを 見てきました ただSwiftUIには もう少し機能があります ここからはラジが担当します ラジ (拍手)
ありがとう ルカ
これから いくつかツールを紹介します まずはデータ管理から すべてのデータに使える 強固な構成を― デザインし構築できるように なります
SwiftUIには多くの データ管理ツールがあります ルカがいくつか お話ししました State Binding Swiftプロパティなどです
残りは私がご案内します まずは外的な変化からです
ルカが使った図に 戻りましょう ユーザはアプリケーションと 関わり合っています これにより Stateは変化し― 新しいビューのコピーを生み ユーザに渡されます
そして外側でイベントが 引き起こされます たとえばタイマーや通知です
しかしビューはStateに 関連付けられています
すべての変化が 集約される場所です
つまり外的な変化にも 対応できるのです ユーザと同様のやり方でです
タイマーが鳴ったり 通知を受けた時も― プロセスは同じです アクションを作成し Stateを切り替え―
ビューが更新され ユーザに送られます
SwiftUIには外的イベントを 示す概念があり― Publisherと呼ばれます
それはCombineされた フレームワークに由来します Combineは時間変化する値を 処理する宣言的APIです
Combineに 深くは立ち入りません 関連のセッションを チェックしてください
Publisherを使う時には メインスレッドで省略します ReceiveOn演算子で 簡単にできるからです 詳しくは “Combine in Practice”をどうぞ
それでは例を見てみましょう Podcast内で 迷子になることがあります 延々と同じ話題を聞かされて 飽き飽きしてしまうのです
そこでタイムスタンプを押し 話題を示すことにします
そのために 現在の時間を示すStateと― 値を示すテキストを加えます
onReceive modifierを 使ってみましょう 時間変化に反応する Publisherは作ってあります それをonReceive modifierに渡します クロージャも用意しました Publisherが省略されると 実行されます
見てください
今までは依存性を 書き込んでいましたが― currentTimeと共に Stateも更新されます SwiftUIが依存性を検知し 自動でラベルが更新されます 手動の無効化や管理は 不要です
(拍手) 簡単に外的変化に 対応できます 外部データについて 話しましょう
BindableObjectプロトコルを 用います カプセル化された 実証済みモデルを― 便利に扱える方法です
すでに構築したモデルを SwiftUIに参照させます
自身が保有し 管理するデータです SwiftUIはその変化に 対応する術を心得ています
別の例を挙げます ユーザの期待は― Podcastが 他のデバイスと同期することです 私はこれに 取り組んできました モデルを構築してきたのです 今こそPodcastプレーヤーに 使う時です お見せしましょう
これがそのモデルです
このモデルをSwiftUIで 使う方法は― BindableObjectプロトコルに 適用するだけです
BindableObjectがあれば Publisherを提供するだけです Publisherは データの変化を示します 結合されたPublisherは― SwiftUIの外的変化を示す 概念です didChangeプロパティに Publisherを渡します PassthroughSubjectが Publisherです
SwiftUIはPublisherに応じて View Hierarchyを更新します
進歩的な手法では― モデルの変更時に Publisherを渡せばいいのです
精度を保つには― 常にモデルチェンジをする 必要があります しかしSwiftUIが― 更新してくれるので 精度に問題は生じません
今BindableObjectに モデルが適用されています 次にモデルの使い方を 示します
二つの原則を 思い出してください すべてのデータは データソースを持ち― それにアクセスする時 依存性が作られます データソースは作りましたが 依存性はまだありません 幸運にも 依存性は容易に作れます
簡単な図を示します View Hierarchyは右の青 モデルは左の緑です
依存性で この二つを結び付けられます ObjectBinding Property Wrapperを使います
これにより それぞれのビューは― モデルに依存性を持ちます
ObjectBindingを ビューに付与すると― フレームワークは 依存性の存在を認識します データにアクセスすれば ビュー更新のタイミングが 分かります
コードでは このように見えます
ビューにObjectBindingが 付与されています
ビューを インスタンス化する時は― モデルの参照を 渡せばよいのです
明確な依存性を イニシャライザに生成し― いつでもビューを インスタンス化できます モデルに依存性を持つのです
このとおりです
この作業で― BindableObject内の変更を ビューは自動で読み込みます 自動で トラッキングするのです 手動による無効化や 同期は不要です
(拍手)
値型を使っている方に 言っておきたいのは― ObjectBindingを 使うべきだということです データの変化が検知され View Hierarchyも更新します
これがObjectBindingによる 依存性の生成です しかし別の手法もあります
間接的な依存性の生成です
先ほどの図に戻りましょう ただし今度は 子要素があります
ここでEnvironmentを 用います “SwiftUI Essentials”を 見た方は― これが優れたカプセル化の 手法だとご存じですね EnvironmentObject modifierで― BindableObjectを Environmentに書き込めます
今モデルはEnvironmentの 中にあります
次にEnvironmentObjectを 使いましょう
このProperty Wrapperで 依存性を生成できます
まだあります これは複数の場所で 使えるのです View Hierarchyのどこでも 使うことができます すべて同じモデルに 依存します
もちろんデータが 変化すると― すべてが自動で更新されます
ObjectBindingと同様の トラッキングです
依存性を書き込めば 後はフレームワークの仕事です すばらしい
(拍手) Podcastプレーヤーを 更新してみます そのために…
こちらですね EnvironmentObjectを ビューに付与します そしてView Hierarchyの 祖先に― EnvironmentObjectで モデルを渡します
プレーヤーを使う度に― SwiftUIは自動で ビューを更新します
ここで疑問を持つでしょう EnvironmentObjectを 使うタイミングは? ObjectBindingだけで 構築することはできます しかしモデルのあちこちに 付与すると扱いづらいです
そこで EnvironmentObjectです データを間接的に渡すのに とても便利です
このように EnvironmentObjectで― モデルを間接的に渡せます 中間にあるビューの インスタンス化は不要です
Environmentは間接的に データを渡す優れた手法です 色やレイアウトの変更に― Environmentが使われるのを 見た方もいるでしょう ルカが言ったようにデータは あらゆる形と形式をとります 色やレイアウトといった値は 単なるデータです 用いた時には 依存性を生成しているのです
Environmentが扱うのは― すべての間接データと 依存性です フレームワークは それを用いて― Dynamic TypeやDark Modeを 提供するのです プレビューで用いて― 色やテーマの値を 与えることもできます
データを扱うパワフルなツールを ご覧いただきました 次にツールの組み合わせ方を 伝授したいと思います
大きなテーマの一つは― すべてのデータが データソースを持つということです データソースを扱う手法には 二つのオプションがあります
一つはState Stateは フレームワークによって― 管理や生成がされている データに効果的です
そしてBindableObjectは 自身が制御するデータ向けで
SwiftUIにデバイス上の データなどを渡しやすいのです
すでに持っているモデルに 使えますね
データソースについて 話してますが― 少し再利用可能な要素の話をします
SwiftUIの利点の一つは ビューのコストが低いことです
性能のために美しい構成を 犠牲にすることはありません 好きに構成しても 高い性能が得られます 躊躇は不要です
ビューを再利用可能にすることに 集中できます
データを扱う時― 切り替えがほぼ不要なことに 気づくと思います その場合は読み取り専用の アクセスが好ましいです
そのためにプロパティと Environmentがあります ビューは値型なので― 自動でデータ変更に対応し ビューを更新できます
普通は変更不能が 好まれますが― たまに値の変更が必要になります
そのためのBindingです
Bindingは データの参照に最適です データを移動しなくても 値の読み書きができます これは再利用に便利です 様々なデータ表現に対する Bindingを使えます StateとObjectBindingに Bindingを付与してみます
Bindingを別のBindingに 紐づけることもできます “$”を頭に付ければ それが可能です 別のツールから Bindingを引き出せます
このパワフルさを 感じてみましょう SwiftUIのコンポーネントは Binding上で動作します Toggleを使ってみましょう ToggleをBooleanに 紐づけます
SwiftUIが美しいのは― ToggleがBooleanの場所を 知る必要がないところです 値の読み込みと 変更ができればいいのです Bindingはこれらの作業を カプセル化し― Toggleへの“関心の分離”を 図れます
データを扱う上で 大きな力となります 精度と“関心の分離”の両方に 便利だからです
再利用可能な要素の構築の話に Stateが出てきませんね Stateはビューと その子要素に隠されています コンポーネントが外部で 動く必要があるなら― Stateは適していません
Stateは原型の作成には 向いています Podcastプレーヤーで 見たようにです しかし大抵の場合 データは SwiftUIの外部に出ます
例えばデータベースなどです そしてBindableObjectなどで 示されます
Stateに手を 伸ばしているなら― 本当にビューにデータが 必要か考えてみてください データとStateを親要素に 引き上げるか― 外部からBindableObjectで 示せるかもしれません
Stateを使う時は注意が必要ですが 強みもあります フレームワークに ボタンがある時などです
ボタンの押下や ハイライトを確認できます ボタンにStateを使うと― 作成時にハイライトを 気にする必要がありません それはボタンが保有する データです
ボタンのようなケースが あるか考えてください あるならStateは便利です ないなら紹介した別の方法を 検討してみてください
再利用可能な要素構築のお話でした
実はすべてのソフトウェアに 適用できる話です
全ソフトウェアはデータと データアクセスを持ちます データを子細に理解して データソースを最小化し― 再利用可能な要素を構築し あらゆるバグを取り払います
SwiftUIではこれらのことが 簡単にできます フレームワークの内側に あるからです
関連する多くのセッションを チェックすることをお勧めします
アプリケーション開発を 変えてくれます
ありがとう (拍手)
-
-
特定のトピックをお探しの場合は、上にトピックを入力すると、関連するトピックにすばやく移動できます。
クエリの送信中にエラーが発生しました。インターネット接続を確認して、もう一度お試しください。