Upgrade to Pro — share decks privately, control downloads, hide ads and more …

ウーニャ、しってる。みんなふんいきでSwiftUIをつかってる。 / iosdc_japan_2022

uhooi
September 10, 2022

ウーニャ、しってる。みんなふんいきでSwiftUIをつかってる。 / iosdc_japan_2022

iOSDC Japan 2022
https://iosdc.jp/2022/

## 参考リンク

### 採用

- CTOが訊く #6 iOSアプリエンジニアとしてDeNAにいる理由 | BLOG - DeNA Engineering
https://engineering.dena.com/blog/2022/09/cto_interview_06/
- 【事業横断】CTO直下ネイティブエンジニア(iOS/Android/Flutter) - 株式会社ディー・エヌ・エー
https://herp.careers/v1/denacareer/ejrQwvTcq2m8
- 【サービス開発】ソフトウェアエンジニア(オープン枠) - 株式会社ディー・エヌ・エー
https://herp.careers/v1/denacareer/4OqhgPs-GpBO
- DeNAのiOSアプリエンジニアと、ざっくばらんにお話ししませんか? - 株式会社ディー・エヌ・エーの中の人のカジュアル面談 - Meety
https://meety.net/matches/BMKFzZYOZYva

### 公式ドキュメント

- Label | Apple Developer Documentation
https://developer.apple.com/documentation/swiftui/label
- LabelStyle | Apple Developer Documentation
https://developer.apple.com/documentation/swiftui/labelstyle
- ViewModifier | Apple Developer Documentation
https://developer.apple.com/documentation/swiftui/viewmodifier

### その他

- View を拡張したい場合は原則として extension を使用し、状態保持が必要な場合のみ `ViewModifier` を実装する。 · Discussion #31 · YusukeHosonuma/Effective-SwiftUI
https://github.com/YusukeHosonuma/Effective-SwiftUI/discussions/31
- Atomic Design | Brad Frost
https://bradfrost.com/blog/post/atomic-web-design/

uhooi

September 10, 2022
Tweet

More Decks by uhooi

Other Decks in Programming

Transcript

  1. ウーニャ、しってる。 みんな雰囲気で SwiftUI をつかってる。 2022.09.10(Sat) 17:15 - 17:55
 iOSDC Japan

    2022 day 0 Track A @the_uhooi
  2. iOS app developer @uhooi @uhooi @the_uhooi

  3. None
  4. None
  5. None
  6. None
  7. 今日は SwiftUI における View の
 「分割」と「命名」について
 みんなで議論したいです #iosdc #ウーニャ #a

    感想をつぶやいてね!
  8. 好きな SwiftUI の View について ツイートしてみましょう! ※なければ「┌|▼▼|┘」とつぶやいてください #iosdc #a #ウーニャ

  9. ・分割と命名を工夫する主な目的は、可読性の向上 ・View 層のみを対象とする  ・MVC や MVVM でいう「V」 ・本発表は私個人の意見 ・(オンライン向け)スクショ OK!

     ・SNS やブログに使ってね 注意
  10. 01 View の「分割」

  11. None
  12. struct var var var some init : View { iconName:

    name: body: View { ( : ) { (iconName) . () . () . ( : , : ) (name) . (.title) . ( : . , : .leading) } . ( ) . ( (.systemBackground) . ( ) . ( : . ( : , : ), : , : , : ) ) } } MonsterListCellView String String HStack spacing 32 Image resizable scaledToFit frame width 68 height 68 Text font frame maxWidth infinity alignment padding 16 background Color cornerRadius 3 shadow color white 0 opacity 0.24 radius 1 x 0 y 1
  13. 現状: body 内が1つの大きな View になっている ↓ ゴール: body 内の View

    を分割して読みやすくする
  14. struct var var var some init : View { iconName:

    name: body: View { ( : ) { (iconName) . () . () . ( : , : ) (name) . (.title) . ( : . , : .leading) } . ( ) . ( (.systemBackground) . ( ) . ( : . ( : , : ), : , : , : ) ) } } MonsterListCellView String String HStack spacing 32 Image resizable scaledToFit frame width 68 height 68 Text font frame maxWidth infinity alignment padding 16 background Color cornerRadius 3 shadow color white 0 opacity 0.24 radius 1 x 0 y 1 Image + Text = Label .elevate()
  15. Label

  16. None
  17. Label を使うと画像とテキストに 関連性を持たせられる!

  18. struct MonsterListCellView: View { var iconName: String var name: String

    var body: some View { } .padding(16) .background( Color(.systemBackground) .cornerRadius(3) .shadow( color: .init(white: 0, opacity: 0.24), radius: 1, x: 0, y: 1 ) - HStack(spacing: 32) { - Image(iconName) - .resizable() - .scaledToFit() - .frame(width: 68, height: 68) - Text(name) - .font(.title) - .frame(maxWidth: .infinity, alignment: .leading) + Label { + Text(name) + } icon: { + Image(iconName) + .resizable()
  19. struct MonsterListCellView: View { var iconName: String var name: String

    var body: some View { } .padding(16) .background( Color(.systemBackground) .cornerRadius(3) .shadow( color: .init(white: 0, opacity: 0.24), radius: 1, x: 0, y: 1 ) - HStack(spacing: 32) { - Image(iconName) - .resizable() - .scaledToFit() - .frame(width: 68, height: 68) - Text(name) - .font(.title) - .frame(maxWidth: .infinity, alignment: .leading) + Label { + Text(name) + } icon: { + Image(iconName) + .resizable()
  20. None
  21. struct func -> some extension where static var init :

    LabelStyle { ( : Configuration) View { ( : ) { configuration.icon . () . ( : , : ) configuration.title . (.title) . ( : . , : .leading) } } } Self == MonsterListCellLabelStyle { monsterListCell: MonsterListCellLabelStyle { . () } } MonsterListCellLabelStyle makeBody configuration LabelStyle HStack spacing 32 scaledToFit frame width 68 height 68 font frame maxWidth infinity alignment MonsterListCellLabelStyle
  22. struct func -> some extension where static var init :

    LabelStyle { ( : Configuration) View { ( : ) { configuration.icon . () . ( : , : ) configuration.title . (.title) . ( : . , : .leading) } } } Self == MonsterListCellLabelStyle { monsterListCell: MonsterListCellLabelStyle { . () } } MonsterListCellLabelStyle makeBody configuration LabelStyle HStack spacing 32 scaledToFit frame width 68 height 68 font frame maxWidth infinity alignment makeBody() 内に
 表示する View を書く MonsterListCellLabelStyle
  23. struct func -> some extension where static var init :

    LabelStyle { ( : Configuration) View { ( : ) { configuration.icon . () . ( : , : ) configuration.title . (.title) . ( : . , : .leading) } } } Self == MonsterListCellLabelStyle { monsterListCell: MonsterListCellLabelStyle { . () } } MonsterListCellLabelStyle makeBody configuration LabelStyle HStack spacing 32 scaledToFit frame width 68 height 68 font frame maxWidth infinity alignment .labelStyle(MonsterListCellLabelStyle()) を
 .labelStyle(.monsterListCell) と書くための
 おまじない MonsterListCellLabelStyle
  24. struct MonsterListCellView: View { var iconName: String var name: String

    var body: some View { Label { Text(name) } icon: { Image(iconName) .resizable() } .padding(16) .background( Color(.systemBackground) .cornerRadius(3) .shadow( color: .init(white: 0, opacity: 0.24), radius: 1, x: 0, y: 1 ) ) } } + .labelStyle(.monsterListCell)
  25. struct MonsterListCellView: View { var iconName: String var name: String

    var body: some View { Label { Text(name) } icon: { Image(iconName) .resizable() } .padding(16) .background( Color(.systemBackground) .cornerRadius(3) .shadow( color: .init(white: 0, opacity: 0.24), radius: 1, x: 0, y: 1 ) ) } } + .labelStyle(.monsterListCell)
  26. ・Label を使うと、画像とテキストに関連性を
  持たせられる ・Label のカスタマイズには LabelStyle を使う Label のまとめ

  27. View の分割方法

  28. struct var var var some : init : View {

    iconName: name: body: View { Label { (name) } icon { (iconName) . () } . (.monsterListCell) . ( ) . ( (.systemBackground) . ( ) . ( : . ( : , : ), : , : , : ) ) } } MonsterListCellView String String Text Image resizable labelStyle padding 16 background Color cornerRadius 3 shadow color white 0 opacity 0.24 radius 1 x 0 y 1
  29. struct var var var some : init : View {

    iconName: name: body: View { Label { (name) } icon { (iconName) . () } . (.monsterListCell) . ( ) . ( (.systemBackground) . ( ) . ( : . ( : , : ), : , : , : ) ) } } MonsterListCellView String String Text Image resizable labelStyle padding 16 background Color cornerRadius 3 shadow color white 0 opacity 0.24 radius 1 x 0 y 1 body 内の
 単一の View が
 少しボリューミー
  30. struct var var var some : init : View {

    iconName: name: body: View { Label { (name) } icon { (iconName) . () } . (.monsterListCell) . ( ) . ( (.systemBackground) . ( ) . ( : . ( : , : ), : , : , : ) ) } } MonsterListCellView String String Text Image resizable labelStyle padding 16 background Color cornerRadius 3 shadow color white 0 opacity 0.24 radius 1 x 0 y 1 どう切り出すのがいい? プロパティ? メソッド? 構造体?
  31. struct var var var some init private var some :

    : View { iconName: name: body: View { monsterLabel . ( ) . ( (.systemBackground) . ( ) . ( : . ( : , : ), : , : , : ) ) } monsterLabel: View { Label { (name) } icon { (iconName) . () } . (.monsterListCell) } } MonsterListCellView String String padding 16 background Color cornerRadius 3 shadow color white 0 opacity 0.24 radius 1 x 0 y 1 Text Image resizable labelStyle 単純な View だから
 プロパティに切り出すのが
 よさそう
  32. View の分割方法(変数) body: View { monsterLabel Label { (name) }

    icon { (iconName) . () }. (.monsterListCell) monsterLabel . ( ) . ( (.systemBackground) . ( ) . ( : . ( : , : ), : , : , : ) ) } var some let = : init Text Image resizable labelStyle padding 16 background Color cornerRadius 3 shadow color white 0 opacity 0.24 radius 1 x 0 y 1 body 内に変数として定義することもできる 使われているのを見たことがないのと、 View を let で保持するのはよくなさそう
  33. View の分割方法(ストアドプロパティ) monsterLabel Label { (name) } icon { (iconName)

    . () }. (.monsterListCell) body: View { monsterLabel . ( ) . ( (.systemBackground) . ( ) . ( : . ( : , : ), : , : , : ) ) } private let = : var some init Text Image resizable labelStyle padding 16 background Color cornerRadius 3 shadow color white 0 opacity 0.24 radius 1 x 0 y 1 他のプロパティを参照しているとエラーになる
 cannot use instance member 'name' within property initializer; property initializers run before 'self' is available Apple のサンプルコードでも使われていないように見える
  34. View の分割方法(コンピューテッドプロパティ) body: View { monsterLabel . ( ) .

    ( (.systemBackground) . ( ) . ( : . ( : , : ), : , : , : ) ) } monsterLabel: View { Label { (name) } icon { (iconName) . () } . (.monsterListCell) } var some init private var some : padding 16 background Color cornerRadius 3 shadow color white 0 opacity 0.24 radius 1 x 0 y 1 Text Image resizable labelStyle Apple のサンプルコードでよく使われている しかしメソッドのみ使うという人も多そう
  35. View の分割方法(メソッド) body: View { () . ( ) .

    ( (.systemBackground) . ( ) . ( : . ( : , : ), : , : , : ) ) } () View { Label { (name) } icon { (iconName) . () } . (.monsterListCell) } var some init private func -> some : monsterLabel padding 16 background Color cornerRadius 3 shadow color white 0 opacity 0.24 radius 1 x 0 y 1 Text Image resizable labelStyle monsterLabel View に引数を渡す場合は
 プロパティでなくメソッドを使う
  36. View の分割方法(構造体) body: View { ( : iconName, : name)

    . ( ) . ( (.systemBackground) . ( ) . ( : . ( : , : ), : , : , : ) ) } : View { iconName: name: body: View { Label { (name) } icon { (iconName) . () } . (.monsterListCell) } } var some init private struct var var var some : MonsterLabel iconName name padding 16 background Color cornerRadius 3 shadow color white 0 opacity 0.24 radius 1 x 0 y 1 String String Text Image resizable labelStyle MonsterLabel 親 View のプロパティを直接参照できないので、
 単純な View だと冗長かもしれない View の外に出せるので、複数の View で利用する場合に使う
  37. 変数 ストアドプロパティ コンピューテッド
 プロパティ メソッド 構造体 使わない 使わない 引数なし、かつ単純な View


    引数あり、かつ単純な View 複数の View で利用する、または複雑な View View の分割方法まとめ
  38. モディファイアの分割方法

  39. struct var var var some init private var some :

    : View { iconName: name: body: View { monsterLabel . ( ) . ( (.systemBackground) . ( ) . ( : . ( : , : ), : , : , : ) ) } monsterLabel: View { Label { (name) } icon { (iconName) . () } . (.monsterListCell) } } MonsterListCellView String String padding 16 background Color cornerRadius 3 shadow color white 0 opacity 0.24 radius 1 x 0 y 1 Text Image resizable labelStyle
  40. struct var var var some init private var some :

    : View { iconName: name: body: View { monsterLabel . ( ) . ( (.systemBackground) . ( ) . ( : . ( : , : ), : , : , : ) ) } monsterLabel: View { Label { (name) } icon { (iconName) . () } . (.monsterListCell) } } MonsterListCellView String String padding 16 background Color cornerRadius 3 shadow color white 0 opacity 0.24 radius 1 x 0 y 1 Text Image resizable labelStyle マテリアルな影を
 切り出したい View の extension? ViewModifier?
  41. struct var var var some private var some : :

    View { iconName: name: body: View { monsterLabel . ( ) . ( (.systemBackground) . ( ) . ( : ) ) } monsterLabel: View { Label { (name) } icon { (iconName) . () } . (.monsterListCell) } } MonsterListCellView String String padding 16 background Color cornerRadius 3 elevate elevation 1 Text Image resizable labelStyle extension func -> some init { ( : CGFloat) View { ( : . ( : , : ), : elevation, : , : elevation ) } } View elevate elevation shadow color white 0 opacity 0.24 radius x 0 y View+Material 単純なモディファイアなので
 ViewModifier を使わないことにする
  42. モディファイアの分割方法(extension) extension func -> some init { ( : CGFloat)

    View { ( : . ( : , : ), : elevation, : , : elevation ) } } View elevate elevation shadow color white 0 opacity 0.24 radius x 0 y モディファイアは View に生えているメソッドで、
 View を返す、とわかるといろいろ捗る
 イメージ View → モディファイアを適用 → 新しい View が返る なので extension でも基本的には同じことが実現できる
  43. モディファイアの分割方法(ViewModifier + extension) モディファイアは View に生えているメソッドで、
 View を返す、とわかるといろいろ捗る
 イメージ View

    → モディファイアを適用 → 新しい View が返る extension func -> some private struct var func -> some init { ( : CGFloat) View { ( ( : elevation)) } } : ViewModifier { elevation: CGFloat ( : Content) View { content. ( : . ( : , : ), : elevation, : , : elevation ) } } View elevate elevation Elevate body content modifier Elevate elevation shadow color white 0 opacity 0.24 radius x 0 y 単純なモディファイアの場合、 ViewModifier を噛ませると 冗長になる
  44. モディファイアの分割方法(ViewModifier + extension) モディファイアは View に生えているメソッドで、
 View を返す、とわかるといろいろ捗る
 イメージ View

    → モディファイアを適用 → 新しい View が返る extension func -> some private struct var func -> some init { ( : CGFloat) View { ( ( : elevation)) } } : ViewModifier { elevation: CGFloat ( : Content) View { content. ( : . ( : , : ), : elevation, : , : elevation ) } } View elevate elevation Elevate body content modifier Elevate elevation shadow color white 0 opacity 0.24 radius x 0 y 単純なモディファイアの場合、 ViewModifier を噛ませると 冗長になる ViewModifier は extension でラップすると モディファイアらしく使える ViewModifier 単体だと使いづらい
  45. None
  46. extension のみ ViewModifier のみ extension + ViewModifier 基本的にはこちらを使う 使わない(必ず extension

    でラップする) extension のみで実現できない場合に使う モディファイアの分割方法まとめ
  47. View の分割場所

  48. struct var var var some private var some : :

    View { iconName: name: body: View { monsterLabel . ( ) . ( (.systemBackground) . ( ) . ( : ) ) } monsterLabel: View { Label { (name) } icon { (iconName) . () } . (.monsterListCell) } } MonsterListCellView String String padding 16 background Color cornerRadius 3 elevate elevation 1 Text Image resizable labelStyle
  49. struct var var var some private var some : :

    View { iconName: name: body: View { monsterLabel . ( ) . ( (.systemBackground) . ( ) . ( : ) ) } monsterLabel: View { Label { (name) } icon { (iconName) . () } . (.monsterListCell) } } MonsterListCellView String String padding 16 background Color cornerRadius 3 elevate elevation 1 Text Image resizable labelStyle View の分割場所はどうする? body? 同一 View? 同一ファイル? 別ファイル?
  50. View の分割場所(body) body: View { monsterLabel Label { (name) }

    icon { (iconName) . () }. (.monsterListCell) monsterLabel . ( ) . ( (.systemBackground) . ( ) . ( : . ( : , : ), : , : , : ) ) } var some let = : init Text Image resizable labelStyle padding 16 background Color cornerRadius 3 shadow color white 0 opacity 0.24 radius 1 x 0 y 1 body 内だと変数として定義するしかない let で保持するのは避けたい
  51. View の分割場所(同一 View) struct var var var some private var

    some : : View { iconName: name: body: View { monsterLabel . ( ) . ( (.systemBackground) . ( ) . ( : ) ) } monsterLabel: View { Label { (name) } icon { (iconName) . () } . (.monsterListCell) } } MonsterListCellView String String padding 16 background Color cornerRadius 3 elevate elevation 1 Text Image resizable labelStyle 他で使わないなら 同一 View でよさそう
  52. View の分割場所(同一ファイルの別 View) struct var var var some private struct

    var var var some : : View { iconName: name: body: View { ( : iconName, : name) . ( ) . ( (.systemBackground) . ( ) . ( : ) ) } } : View { iconName: name: body: View { Label { (name) } icon { (iconName) . () } . (.monsterListCell) } } MonsterListCellView MonsterLabel String String MonsterLabel iconName name padding 16 background Color cornerRadius 3 elevate elevation 1 String String Text Image resizable labelStyle 単一の View のみで使うなら、View の外に出す必要はない エクステンションは構造体内に定義できないので出すしかない
  53. View の分割場所(別ファイル) struct var var var some : : View

    { iconName: name: body: View { Label { (name) } icon { (iconName) . () } . (.monsterListCell) } } MonsterLabel String String Text Image resizable labelStyle 複数の View で利用するなら別ファイルがいい
  54. body 同一 View 同一ファイル
 の別 View 別ファイル 使わない プロパティ、メソッド、単一の View

    で利用する構造体 同一ファイル内の複数の View で利用する構造体、
 単一の View で利用するエクステンション 複数の View で利用する構造体・エクステンション View の分割場所まとめ
  55. モディファイアの分割是非

  56. struct var var var some private var some : :

    View { iconName: name: body: View { monsterLabel . ( ) . ( (.systemBackground) . ( ) . ( : ) ) } monsterLabel: View { Label { (name) } icon { (iconName) . () } . (.monsterListCell) } } MonsterListCellView String String padding 16 background Color cornerRadius 3 elevate elevation 1 Text Image resizable labelStyle
  57. struct var var var some private var some : :

    View { iconName: name: body: View { monsterLabel . ( ) . ( (.systemBackground) . ( ) . ( : ) ) } monsterLabel: View { Label { (name) } icon { (iconName) . () } . (.monsterListCell) } } MonsterListCellView String String padding 16 background Color cornerRadius 3 elevate elevation 1 Text Image resizable labelStyle .padding(_:) は 切り出したプロパティに含めないの?
  58. struct var var var some private var some : :

    View { iconName: name: body: View { monsterLabel . ( ) . ( (.systemBackground) . ( ) . ( : ) ) } monsterLabel: View { Label { (name) } icon { (iconName) . () } . (.monsterListCell) } } MonsterListCellView String String padding 16 background Color cornerRadius 3 elevate elevation 1 Text Image resizable labelStyle .padding(_:) は 切り出したプロパティに含めないの? →外から決めるべきことは含めない パディングは Label 単体では決まらず、 配置場所によって決まる
  59. struct func -> some extension where static var init :

    LabelStyle { ( : Configuration) View { ( : ) { configuration.icon . () . ( : , : ) configuration.title . (.title) . ( : . , : .leading) } } } Self == MonsterListCellLabelStyle { monsterListCell: MonsterListCellLabelStyle { . () } } MonsterListCellLabelStyle makeBody configuration LabelStyle HStack spacing 32 scaledToFit frame width 68 height 68 font frame maxWidth infinity alignment MonsterListCellLabelStyle
  60. struct func -> some extension where static var init :

    LabelStyle { ( : Configuration) View { ( : ) { configuration.icon . () . ( : , : ) configuration.title . (.title) . ( : . , : .leading) } } } Self == MonsterListCellLabelStyle { monsterListCell: MonsterListCellLabelStyle { . () } } MonsterListCellLabelStyle makeBody configuration LabelStyle HStack spacing 32 scaledToFit frame width 68 height 68 font frame maxWidth infinity alignment サイズを固定する場合は切り出す MonsterListCellLabelStyle
  61. struct func -> some extension where static var init :

    LabelStyle { ( : Configuration) View { ( : ) { configuration.icon . () . ( : , : ) configuration.title . (.title) . ( : . , : .leading) } } } Self == MonsterListCellLabelStyle { monsterListCell: MonsterListCellLabelStyle { . () } } MonsterListCellLabelStyle makeBody configuration LabelStyle HStack spacing 32 scaledToFit frame width 68 height 68 font frame maxWidth infinity alignment 左寄せにするのが目的で 外から決めるものではない MonsterListCellLabelStyle
  62. ・外から決めるべきなら切り出さない  ・例: .padding(_:)、.frame(width:height:) ・余白やサイズを固定したいなら切り出す モディファイアの分割是非まとめ

  63. 分割の上限

  64. struct var var var some private var some : :

    View { iconName: name: body: View { monsterLabel . ( ) . ( (.systemBackground) . ( ) . ( : ) ) } monsterLabel: View { Label { (name) } icon { (iconName) . () } . (.monsterListCell) } } MonsterListCellView String String padding 16 background Color cornerRadius 3 elevate elevation 1 Text Image resizable labelStyle
  65. struct var var var some private var some : :

    View { iconName: name: body: View { monsterLabel . ( ) . ( (.systemBackground) . ( ) . ( : ) ) } monsterLabel: View { Label { (name) } icon { (iconName) . () } . (.monsterListCell) } } MonsterListCellView String String padding 16 background Color cornerRadius 3 elevate elevation 1 Text Image resizable labelStyle .elevateBackground(elevation:) のようにまとめたほうがよくない?
  66. struct var var var some private var some : :

    View { iconName: name: body: View { monsterLabel . ( ) . ( (.systemBackground) . ( ) . ( : ) ) } monsterLabel: View { Label { (name) } icon { (iconName) . () } . (.monsterListCell) } } MonsterListCellView String String padding 16 background Color cornerRadius 3 elevate elevation 1 Text Image resizable labelStyle .elevateBackground(elevation:) のようにまとめたほうがよくない? →そうかも どこまで分割するかは好みだけど、 body には「構造」と外から決めるものだけ残して 「装飾」は外出しすると見やすいかも
  67. ・どこまで分割するかは好み ・body には構造と外から決めるものだけ残すと
  読みやすい 分割の上限まとめ

  68. View の「分割」まとめ

  69. ・Label など標準で用意されている View を活用する ・View を let で保持しない ・View の分割はスコープを最小にする

    ・body は「構造」のわかりやすさを意識する View の「分割」まとめ
  70. 02 View の「命名」

  71. 「View 単体の意味」と
 「各画面における役割」で分けて 考えるべき

  72. View 単体の意味 Label Image Text

  73. 各画面における役割 画面全体(Page) 画面の一部分
 (Organism)

  74. 役割は1つ以上の View をラップする 単体 単体 単体 役割 単体 役割 単体

    単体 単体 役割 単体 役割 役割 View に役割を付与するイメージ
  75. 実画面と設計の対応イメージ 単体 単体 単体 役割 単体 役割 役割 ヘッダー 画面の一部分

    UINavigationBar UICollectionViewCell UICollectionViewCell UICollectionViewCell 画面全体
  76. 「View 単体の意味」の命名ルール

  77. 「View 単体の意味」の命名ルール プロトコルや型の名前を末尾に付ける struct var var var some private var

    some : : View { iconName: name: body: View { monsterLabel . ( ) . ( (.systemBackground) . ( ) . ( : ) ) } monsterLabel: View { Label { (name) } icon { (iconName) . () } MonsterListCellView String String padding 16 background Color cornerRadius 3 elevate elevation 1 Text Image resizable View プロトコルに準拠しているから「◦◦View」 型は View だが、 中身が Label のみなので「◦◦Label」
  78. 「View 単体の意味」の命名ルール Apple のサンプルコードや UIKit を参考にする(任意) struct var var var

    some private var some : : View { iconName: name: body: View { monsterLabel . ( ) . ( (.systemBackground) . ( ) . ( : ) ) } monsterLabel: View { Label { (name) } icon { (iconName) . () } MonsterListCellView String String padding 16 background Color cornerRadius 3 elevate elevation 1 Text Image resizable UICollectionViewCell のように使うので「◦◦CellView」
  79. ・プロトコルや型の名前を末尾に付ける ・Apple のサンプルコードや UIKit などを
  参考にする(任意) 「View 単体の意味」命名まとめ

  80. 「各画面における役割」の命名ルール

  81. 「各画面における役割」の命名ルール ルールを決めたら README に明記する View プロトコルに準拠しているから「◦◦View」

  82. 「各画面における役割」の命名ルール アトミックデザインなどを参考にする(任意) View プロトコルに準拠しているから「◦◦View」

  83. 「各画面における役割」の命名ルール 役割を細かく分け過ぎない View プロトコルに準拠しているから「◦◦View」 SwiftUI で ここまで分けると 冗長かもしれない

  84. ・ルールを決めたら README に明記する ・アトミックデザインなどを参考にする(任意) ・役割を細かく分け過ぎない 「各画面における役割」命名まとめ

  85. View の「命名」まとめ

  86. ・View 単体の意味と、全体の役割を分けて考える ・全体の設計をドキュメント化する View の「命名」まとめ

  87. まとめ

  88. ・言語化するのが大事 ・プロジェクトごとにルールをドキュメント化する ・できるところから適用してみてください ・今日の発表でわからなかったら
  何でも聞いてください! まとめ