WWDC Quick Look 💓 By SwiftGGTeam
SwiftUI essentials

SwiftUI essentials

元の動画を見る

Highlight

SwiftUI 入門から中級者向けの基礎整理セッションです。講演者は「ペット trick ランキング」アプリを通じて、最も基本的な View 概念から List、Navigation、カスタムコンポーネント、状態管理、他フレームワークとの統合までを解説します。


主要内容

SwiftUI 入門から中級者向けの基礎整理セッションです。講演者は「ペット trick ランキング」アプリを通じて、最も基本的な View 概念から List、Navigation、カスタムコンポーネント、状態管理、他フレームワークとの統合までを解説します。

核心内容は 3 つの層に分かれます。第 1 層は View の本質: SwiftUI の View は宣言的な記述であり、長期間存在するオブジェクトインスタンスではありません。状態が変化するたびに SwiftUI は View body を再評価し、新しい記述を生成して効率的にレンダリングを更新します。第 2 層は合成: コンテナビュー(HStack、VStack、List)と View Modifier でシンプルなビューを複雑な UI に組み合わせます。第 3 層は状態駆動: @State@Bindable@Environment などのプロパティラッパーでデータ依存を宣言し、SwiftUI が UI 更新を自動処理します(00:07)。

セッションでは SwiftUI が他フレームワークとどう共存するか — UIKit 相互運用、SwiftData 永続化、Widget 拡張 — についても相当な時間を割き、アプリ全体を書き直すことなく段階的採用をネイティブにサポートすることを強調しています(21:08)。


詳細

宣言的 View の本質

SwiftUI の View は値型(struct)であり、長期間存在するオブジェクトインスタンスではありません。状態が変化するたびに SwiftUI は View body を再評価し、新しい記述を生成して効率的にレンダリングを更新します。ビューのライフサイクルを手動管理する必要はなく、「UI がどうあるべきか」を記述するだけです(00:09)。

// 基本的な View 宣言
HStack {
    Label("Pet Tricks", systemImage: "pawprint")
    Spacer()
    Text("Rank")
}

キーポイント:

  • HStack は子ビューを水平に並べるコンテナビュー
  • Label はアイコンとテキストを組み合わせる SwiftUI 組み込みの複合コントロール
  • Spacer は残りのスペースを自動的に占有し、レイアウトの整列を実現

List と ForEach の組み合わせ

List は最もよく使われるコンテナビューの 1 つです。コレクションパラメータを受け取り、内部で ForEach ビューを自動作成して各要素の行を生成します。再利用とスクロール性能を手動管理する必要はありません(02:56)。

// List がコレクションの各要素の行を自動作成
List(pets) { pet in
    HStack {
        Text(pet.name)
        Text(pet.trick)
    }
}

キーポイント:

  • List のコレクションパラメータが ForEach ビューを自動作成
  • 各要素が HStack 行ビューに対応
  • SwiftUI がスクロール性能とビュー再利用を自動処理

View Modifier のチェーン

View Modifier は SwiftUI のもう 1 つの核心パターンです。基本ビューを「修飾」し、修飾された新しいビューを返します。複数の Modifier をチェーンでき、効果の階層を明確に形成します(06:17)。

// View Modifier のチェーン
Image("whiskers")
    .clipShape(Circle())
    .shadow(radius: 5)
    .overlay(Circle().stroke(Color.green, lineWidth: 2))

キーポイント:

  • clipShape(Circle()) で画像を円形にクロップ
  • shadow(radius:) でシャドウ効果を追加
  • overlay で上に緑色のボーダーを重ねる
  • Modifier の順序が効果の適用順序を決定

カスタム View のカプセル化

UI が複雑になると、ビュー階層をカスタム View にカプセル化できます。カスタム View は View プロトコルに準拠し、body プロパティを提供するだけです。View は値型なので、ビューを分割しても性能に悪影響はありません(07:02)。

// カスタム View のカプセル化
struct PetRow: View {
    let pet: Pet

    var body: some View {
        HStack {
            ProfileImage(for: pet)
            VStack(alignment: .leading) {
                Text(pet.name)
                Text(pet.trick)
            }
        }
    }

    private var profileImage: some View {
        Image(pet.imageName)
            .clipShape(Circle())
            .shadow(radius: 5)
    }
}

キーポイント:

  • カスタム View に入力パラメータとしてプロパティを追加可能
  • private 計算プロパティでコードを整理
  • List(pets) { PetRow(pet: $0) } など任意の場所で再利用可能

状態駆動の UI 更新

SwiftUI の 3 つ目の核心機能は状態駆動です。状態が変化すると、SwiftUI はその状態に依存する View body を自動的に再計算し UI を更新します。手動 UI 更新のボイラープレートと更新漏れバグを排除します(08:50)。

// 状態駆動の条件レンダリング
struct PetRow: View {
    let pet: ObservablePet

    var body: some View {
        HStack {
            Text(pet.name)
            if pet.hasAward {
                Image(systemName: "trophy.fill")
            }
        }
    }
}

キーポイント:

  • pet.hasAward が変化すると SwiftUI が body を自動再計算
  • 条件レンダリングが自動更新。手動リフレッシュ不要
  • SwiftUI が View body で使用されるプロパティを追跡し、依存関係を構築

@State と Binding

@State は View の内部状態ソースを作成します。Binding は他の View の状態への双方向参照です。Binding により子 View が親 View の状態を変更でき、状態共有を実現します(09:30)。

// @State で内部状態を作成
struct RatingView: View {
    @State private var rating = 0

    var body: some View {
        HStack {
            Button("-") { rating -= 1 }
            Text("\(rating)")
            Button("+") { rating += 1 }
        }
    }
}

// Binding で状態を共有
struct RatingContainer: View {
    @State private var rating = 0

    var body: some View {
        VStack {
            Gauge(value: rating, in: 0...10)
            RatingView(rating: $rating)  // Binding を渡す
        }
    }
}

struct RatingView: View {
    @Binding var rating: Int  // Binding を受け取る

    var body: some View {
        HStack {
            Button("-") { rating -= 1 }
            Text("\(rating)")
            Button("+") { rating += 1 }
        }
    }
}

キーポイント:

  • @State で SwiftUI がプロパティストレージを管理
  • $ プレフィックスで Binding を作成し、双方向バインディングを実現
  • 子 View が Binding を変更すると親 View の状態が更新
  • 状態共有で複数の View が同期更新

アニメーション統合

SwiftUI のアニメーションは状態駆動の更新メカニズムの上に構築されています。withAnimation で状態変化をラップすると、SwiftUI がデフォルトアニメーションを自動適用します。アニメーションカーブやトランジション効果もカスタマイズ可能です(11:40)。

// 状態駆動のアニメーション
Button("+") {
    withAnimation {
        rating += 1
    }
}

// カスタムトランジション効果
Text("\(rating)")
    .contentTransition(.numericText())

キーポイント:

  • withAnimation が状態変化をラップしてアニメーションをトリガー
  • .numericText() トランジションは数値変化に適している
  • アニメーションは宣言的。タイミングの手動制御不要

適応型コントロール

SwiftUI のコントロールは正確な視覚的構造ではなく「目的の記述」です。Button は「ラベル付きアクション」を宣言するだけで、具体的なスタイルはコンテキストに応じて自動適応します。リストではスワイプ操作、メニューではメニュー項目になります(14:09)。

// 適応型検索
List(pets) { pet in
    PetRow(pet: pet)
}
.searchable(text: $searchText)

キーポイント:

  • .searchable modifier が検索機能を自動追加
  • iOS ではリスト上にオーバーレイ、macOS ではドロップダウンメニューを表示
  • コントロールがコンテキストに応じてスタイルを自動適応

プラットフォーム適応と相互運用

SwiftUI はすべての Apple プラットフォームをサポートします。同じコードが異なるプラットフォームのデザインガイドラインに自動適応します。macOS はマルチウィンドウ、watchOS はデジタルクラウンスクロール、visionOS は空間コンテンツをサポートします(15:54)。

// watchOS デジタルクラウンスクロール
.scoreboard
.digitalCrownRotation($rating, from: 0, through: 10)

// UIKit 相互運用
struct UIKitView: UIViewRepresentable {
    func makeUIView(context: Context) -> UIViewType {
        // UIKit ビューを作成
    }
    func updateUIView(_ uiView: UIViewType, context: Context) {
        // UIKit ビューを更新
    }
}

キーポイント:

  • .digitalCrownRotation でデジタルクラウン制御を有効化
  • UIViewRepresentable で SwiftUI 内に UIKit ビューを埋め込み
  • UIHostingController で UIKit 内に SwiftUI ビューを埋め込み

重要ポイント

  1. UIKit からの移行: 一度にすべて書き直そうとしない。 SwiftUI の UIViewRepresentableUIHostingController により、UIKit 内に個別の SwiftUI ビューを埋め込む、またはその逆が可能です。独立した境界の明確な機能(設定ページ、オンボーディングなど)を見つけ、まず SwiftUI で実装し、チームの学習曲線と開発効率を検証しましょう。

  2. 新規プロジェクトは SwiftUI を直接使用。 Apple はすでに多くの新規アプリで SwiftUI を使用しており、フレームワークの成熟度はもはや問題ではありません。SwiftData でデータ永続化を組み合わせ、@Query で UI とデータを自動同期 — 技術スタック全体が宣言的です。ただし、高度にカスタマイズされたスクロール動作や複雑なタッチイベント処理など、一部の高度なカスタマイズシナリオでは UIKit に戻る必要がある場合があります。

  3. View の値型特性を活用してコードを分割。 大きな View を小さな View に分割し、各 View が明確な入力パラメータを受け取るようにします。1 つの View の body に 200 行書かない — 5 つのサブ View に分割すれば保守性が向上し、性能への悪影響もありません。SwiftUI は変化した状態に依存する View のみを効率的に更新します。


関連セッション

コメント

GitHub Issues · utterances