BETA

SwiftUI Tutorial 3: Handling User Input

投稿日:2019-09-02
最終更新:2019-09-02

・FunctionBuildersの中で if が使える。
(ただし、なるべく modifier の中で書くこと、って SwiftUI Essential で言ってた)

Image(systemName: "") はベクター画像だから、 .foregroundColor(.yellow) で色指定できる

・プレビューを足したり修正したら、プレビューは必ず手動リフレッシュ(「Resume」を押す) が必要。

・「"Binding" は、mutable state の参照のように振る舞う。
Control(Toggleとか) の On / Off をするたび、Controlはバインディングをビューの状態を更新するために使う。」

【Control】-----<Binding 経由で State を変更>-----> 【View's State】<---------- 【View】(state更新ごとに再描画)

ForEach と協調するため、データソースを引数として取らないタイプの List の init がある。

List {  // コレクションを取らない!  
    ForEach(landmarkData) { landmark in  // ...まぁ、ForEachが取って、処理するんだけどな  
        ...  
    }  
}  

・Toggle のイニシャライザ。

Toggle(isOn: <Binding<Bool>>, label: {})

Button にも、「押下時のアクション」「見た目」という、そっくりのイニシャライザがある

Button(action: { 押下時の処理 }{ 見た目 } )

List(dataSource) { ... } がイテレーションをするのであって、
List {} はイテレーションしない(代わりに、中に ForEach を書き、そいつに反復させるだろう。)

すなわち、 List それ自体は、イテレーションすることを必ずしも意味しない。

・「Toggle(Control) に、モデルのバインディングを渡す」という表現は正しい。

・ $ を使うことで、「@State な変数のバインディング」「@Publish な変数のバインディング」、
「プロパティのバインディング」などを抽出できる。
さしずめこんな感じか...。

モデル「バインディングあげます!変更のための穴開けといたから!これ経由して俺の値を変えてくれ!」  

ビューでイベント発生 ---> バインディング経由で、モデルの値が write される

・Section 4: ストレージのために、Observable Object を使え

Observable Object とは?
=> ストレージからビュー方向にバインド可能な、
SwiftUIのEnvironmentにおける、アプリのデータのためのカスタムオブジェクト。

// クラスなのか...。  
// `ObservableObject` ... Combine由来  
final class UserData: ObservableObject {  
    @Published var showFavoriteOnly = false  
    @Published var landmarks = landmarkData  
}  

SwiftUIは、ビューに影響を与える Observable Object の変化を、Subscribeすることで常に監視しており、
値の変化とともに、正しいビューを描画する。
Observable Object は、値の変化を Publish する必要があり、購読者がそれに気付けるよう、
各プロパティに @Published をつける

・Section 5: Observable Object を作ったら、それをビューのデータソースとして使う

environment object を使うときは、modifier で登録しないとだめ

window.rootViewController = UIHostingController(  
                rootView: LandmarkList()  
                    .environmentObject(UserData())  // modifierを使い、environment object を登録  
            )  

さもないと、こんなランタイムエラーになる

Fatal error: No observable object of type UserData.Type found.  
A View.environmentObject(_:) for UserData.Type may be missing as an ancestor of this view.: file  

EnvironmentObject は初期値もなく、特にinit でセットすることもなくコンパイルエラーなしに定義できる特別扱いをされている。
さしずめ、environmentObject() modifier は、その初期値を与えている、ということであり、
それゆえに、それを忘れたら Swift世界に重大な矛盾が生じ、やがて崩壊する(ランタイムエラー)のだろう

1度Listのビューで登録すれば、その EnvironmentObject は Detail ページでも使えている。
Detail には modifier で登録してないのに。

「一覧画面と詳細画面で、データの一貫性を保ちたい」ときは、
Environment Object を使おう。
詳細画面でお気に入り登録すれば、それが即座に一覧画面に反映されている。

感想

このトピックが、チュートリアル中、最も多くの射程を内包しているのではないのか...。
ここをスラスラ書けるようになるのが、当面のSwiftUI力の目指すところだろう....

SwiftUIにふれるだけで、ビューとデータの分離をいやでも意識せざるを得なくなる。ここがフロント最前線。
Webフロントエンドも書けるようになる一助にも、気づいたらなってたりしないかな。

技術ブログをはじめよう Qrunch(クランチ)は、プログラマの技術アプトプットに特化したブログサービスです
駆け出しエンジニアからエキスパートまで全ての方々のアウトプットを歓迎しております!
or 外部アカウントで 登録 / ログイン する
クランチについてもっと詳しく

この記事が掲載されているブログ

備忘録ほどの価値もない走り書き

よく一緒に読まれる記事

0件のコメント

ブログ開設 or ログイン してコメントを送ってみよう
目次をみる
技術ブログをはじめよう Qrunch(クランチ)は、プログラマの技術アプトプットに特化したブログサービスです
or 外部アカウントではじめる
10秒で技術ブログが作れます!