SwiftUIで意味的最小粒度のViewを作るための個人的思想

開発環境

$ xcodebuild -version
Xcode 14.3
Build version 14E222b

モチベーション

SwiftUIのViewの組み方は色々ある。今の自分の考えをメモしておく。

先行事例

iOSDC Japan 2022でウホーイさんが発表された内容がしっくりきている。

speakerdeck.com

  • 単純なViewならプロパティに切り出す
  • 引数渡す場合はメソッドに切り出す
  • paddingなどの利用側起因で値を変更したいmodifierは利用側で付与する

個人の思想

意味的な最小の粒度で分割したい。

import SwiftUI

struct ContentView: View {
    var body: some View {
        ScrollView {
            VStack(
                alignment: .leading,
                spacing: 8
            ) {
                Text("hoge section")
                    .font(.headline)
                    .padding(.horizontal, 20)
                ScrollView(
                    .horizontal,
                    showsIndicators: false
                ) {
                    LazyHStack(spacing: 24) {
                        ForEach(0..<10) { _ in
                            AsyncImage(url: URL(string: "https://placehold.jp/150x150.png"))
                                .fixedSize()
                                .frame(width: 150)
                        }
                    }
                    .padding(.horizontal, 20)
                }
            }
        }
    }
}

import SwiftUI

struct ContentView: View {
    private static var horizontalPadding: CGFloat = 20
    
    var body: some View {
        ScrollView {
            SectionView(
                title: "hoge section",
                horizontalPadding: Self.horizontalPadding
            )
        }
    }
}

private struct SectionView: View {
    let title: String
    let horizontalPadding: CGFloat

    var body: some View {
        VStack(
            alignment: .leading,
            spacing: 8
        ) {
            header
                .padding(.horizontal, horizontalPadding)
            items
        }
    }
    
    private var header: some View {
        Text(title)
            .font(.headline)
    }
    
    private var items: some View {
        ScrollView(
            .horizontal,
            showsIndicators: false
        ) {
            LazyHStack(spacing: 24) {
                ForEach(0..<10) { _ in
                    SectionItemView(url: URL(string: "https://placehold.jp/150x150.png"))
                }
            }
            .padding(.horizontal, horizontalPadding)
        }
    }
}

private struct SectionItemView: View {
    let url: URL?

    var body: some View {
        AsyncImage(url: url)
            .frame(width: 150)
    }
}
  • インスタンス間で共通の値はstaticなpropertyで値を持たせる
    • horizontalPadding
  • Xcode Previewsを使いたいViewはstructとして切り出す
    • いわゆる子Viewでもプレビューさせたい場合はstructとして切り出す
  • bodyはスッキリさせる
    • header, items
    • ひと目見てViewを想像できるようにしておく
  • 少なくともViewのstructのプロパティはletで宣言する
    • Swift の struct の stored property は var にしよう - Qiita 文脈
      • 勉強にさせていただいた記事
      • varでも安全だからvarにしておこう、という脳のインデックスを消費したくないのでletにしてる
      • varがある場合はmutating funcの存在を気にする必要がある
      • letなら上記を考えなくて済む、もともと安全(あくまで自分の考え(保険))

現時点での思想を列挙した。明日には気持ちが変わってるかもしれない。

チーム開発ならそのチームの文化に合わせたり、気になるところがあったら話題に出していけば良い。この記事5分ぐらいで書いたから適当なこと言ってるかもしれない。じゃあな!