Skip to content

Instantly share code, notes, and snippets.

@omochi
Created July 17, 2019 03:01
Show Gist options
  • Save omochi/b62bebf1bfadbf045081bda60f8d65ed to your computer and use it in GitHub Desktop.
Save omochi/b62bebf1bfadbf045081bda60f8d65ed to your computer and use it in GitHub Desktop.

https://developer.apple.com/tutorials/swiftui/handling-user-input

このチュートリアルの最後の場面で、LandmarkDetail画面で、お気に入りのスターを表示する処理と、タップによってスターをオン/オフする処理が実装される。

この画面の設計が気持ち悪い。

まず、LandmarkDetailはinitでlandmark: Landmarkを受けてvarに保存している。 それを、self.landmark.nameなどの表示に使っている。

一方、LandmarkDetailは@EnvironmentObjectuserData: UserDataも暗黙に受け取っている。 そして、self.landmark.idを使ってself.userData.landmarksからインデックスを引いてきて、self.userData.landmarks[index]として、Landmark型を取り出す処理がある。 こうやって取り出した方のLandmarkは、isFavoriteの方の表示に使っている。

このように、引数で受けたLandmarkを静的な値の表示、UserDataの中のLandmarkを動的な値の表示にと使い分けている。この作りは、値が静的か動的かどうかという必要のない関心をコードに生じさせてしまっていると思う。

また、LandmarkDetailは一つのランドマークを表示するための画面なのに、UserData型固有のデータ構造に依存したコードになってしまっていて、これも必要のない関心が埋め込まれていると思う。

この画面は本来、@Binding var landmark: Landmarkなどとやって、表示するLandmark一つだけに依存させるべきで、画面表示側で、必要であればこれをUserData.landmarksと結合させる、といった構造になるべきだと思う。

ただ現状、SwiftUIにはlandmarks: [Landmark]からある一要素に対するBinding<Landmark>を作る標準の道具が無いような気がする?

@omochi
Copy link
Author

omochi commented Jul 19, 2019

それだとViewが自らの認識の外の通知を受け取れる余地がないので…

確かにそうだけど、「大本(A)」以外からの変更通知を(Bで)受け取るシチュエーションはおかしいのでは?
他の場所(C)で変更が発生するとしても、それを(Bで)受け取る必要があるとしたら、同じ実体を意味しているはずなので、
そのほかの場所(C)から大本(A)に反映するような形にした上で、(Bでは)大本(A)経由で受け取るようにすると思います。

ただその大本の管理主体がコンテキストオブジェクトであるEnvironmentObjectとなるとは思います。

@takasek
Copy link

takasek commented Jul 19, 2019

あー
大本=landmarks だと思って話してました

大本=A=EnvironmentObject
とすれば、認識一致してそう

landmarks: [Landmark]からある一要素に対するBindingを作る標準の道具

ができるときには、
引数としてEnvironmentを取りつつラクに書けると嬉しい世界なのかな

@omochi
Copy link
Author

omochi commented Jul 19, 2019

引数としてEnvironmentを取りつつラクに書けると嬉しい

そう思います。

@sidepelican
Copy link

sidepelican commented Jul 30, 2019

(Twitter@iceman5499です。)

Xcode11 Beta5 くらいからいつの間にか Binding が自分で生成できるようになった( init(get: @escaping () -> Value, set: @escaping (Value) -> Void) が生えた)ので

landmarks: [Landmark]からある一要素に対するBindingを作る標準の道具

これができるようになったように見えます。
Bindingとしての取り出しはやや煩雑ですが、ある程度理想的な形でかけるようになりました

https://gist.github.com/sidepelican/330ca3255cffcf13cd5352d5935040c7

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment