SwiftUI Tutorials: 4日目

今日はこれ「Handling User Input」にチャレンジ。いよいよUIによる状態変化と、Combine.framwを用いた状態変化に追従したUI更新。

  • @State修飾子: Viewの持つプロパティに指定することで、このプロパティの変更と共にViewの表示がinvalidateされ、自動的にbodyが再計算される
    • Stateへのbindingへのアクセスには、該当プロパティ名に $ の接頭辞をつける (e.g. $propertyName)
      • e.g. Toggle(isOn: $someState) { //Switch UIの値変更時処理 }
    • State修飾子をもつプロパティは、そのプロパティを持つViewクラスのbodyからのみにアクセスを限定するべき。そのためアクセス修飾子をprivateとする
  • @EnvironmentObject修飾子: State同様に値の変更に伴ってView表示がinvalidateされる。SceneDelegateや表示元Viewなど、ビュー階層の上(親)側からデータを受け取る場合に指定する
    • BindableObjectプロトコルに適合する
      • PassthroughSubject<Output, Failure>クラスを継承したプロトコル didChange を定義する
        • 自信のプロパティ変更時(didSet)に didChange.send(self)を実行して、値の変更をpublishする
      • @EnviromentObjectと逆に、View階層の下にデータを受け流すばあいはdownwardView.enviromentObject(bindableData) のように記述する

こんな感じだとおもう。

しかし、tableのフィルタ表示が簡単すぎる。データをForEachしながら、セルの表示が必要なければ何もビューを返さなければ良いのだ。UITableViewDataSourceのように、numberOfCell… や cellForRow… など記述する必要がないので、不注意な実装での典型例だった、データ配列アクセス時のout of boundsによる例外はなくなりそうだ。

また、canvasのプレビュー上で、スイッチなどコントロールを操作して実際の画面変化を確かめられるので、シミュレータで実行確認するまでもないのも素晴らしい。

しかし、ForEachで回しているので、ビューは返さなくても、空(高さ0)のセルは存在するのだろうか…? とふと疑問になった。

ちなみに、@State, @EnviromentObject は、この書き方から分かる通り、Swift 5.1で導入された、property gelegate という仕組みを利用している。

また、今回も現時点(2019/06/09)で、チュートリアルにいくつか誤りがあったのでメモしておく。正式リリース時までには修正されると思う。

  • Create a Favorite Button for Each Landmark

    • MapView(landmark: landmark)
      • MapView.init(landmark:)イニシャライザが存在しない。MapView(coordinate: landmark.coordinate) とするか、イニシャライザを実装すれば良い
    • Text(landmark.park).font(caption)
      • 正しくは、.font(.caption)

コメントを残す