SwiftUI:概要、主要概念、View Protocol

著者: IT Sectr 公開日: 2026-04-30 読了時間: 8 分

SwiftUIは、Appleエコシステムのすべてのプラットフォーム向けにユーザーインターフェースを構築するための宣言型フレームワークです。手順を命令的に記述する代わりに、開発者はインターフェースの見た目を宣言し、SwiftUIがレンダリングと更新を管理します。Apple Developer Documentation(2025)によると、SwiftUIはiOS 15+、iPadOS 15+、macOS 12+、watchOS 8+、tvOS 15+をサポートし、すべてのインターフェースコンポーネントの基本構成要素としてView Protocolを使用します。

重要なポイント

  • SwiftUIはAppleの宣言型フレームワークで、開発者がインターフェースを記述すると更新が自動的に実行されます。
  • View Protocolbodyプロパティは、SwiftUIのUIコンポーネントの基盤であり、ビュー構成を通じて画面の説明を返します。
  • Property Wrappers(@State、@Binding、@ObservedObject、@StateObject)は状態を管理し、データ変更時に再レンダリングをトリガーします。
  • NavigationStack(iOS 16+)は、型安全なルートと宣言型トランジションを備えた最新のナビゲーションAPIです。
  • Modifierは、クラス継承なしでビューの外観と動作をカスタマイズするための呼び出しチェーンです。

SwiftUIとは?

SwiftUIは、2019年にAppleが新しいプロジェクトでUIKitを置き換えるために導入した宣言型フレームワークです。UIViewインスタンスを手動で作成して階層に追加する代わりに、開発者はViewプロトコルに準拠した構造体を通じてインターフェースを記述します。SwiftUIは現在の状態と新しい状態の差分を自動的に計算し、独自のレンダリングエンジンを使用して変更された部分のみを再レンダリングします。

フレームワークは値セマンティクス(クラスではなく構造体)を使用してSwiftで書かれており、UIコンポーネントを軽量かつスレッドセーフにします。Objective-CランタイムのためにUIViewControllerが200+バイトになる可能性があるUIKitとは異なり、SwiftUI Viewは数バイトの単純な構造体です。これはメモリが限られているwatchOSにとって特に重要です。

SwiftUIのクロスプラットフォーム

同じViewの記述がiPhone、iPad、Mac、Apple Watch、Apple TV、Apple Vision Proで動作します。SwiftUIはプラットフォームに合わせてインターフェースを適応させます:iOSではタッチジェスチャー、macOSではキーボードコンビネーション、watchOSではDigital Crownスクロール。これにより、複数のAppleプラットフォームでアプリをリリースする企業の開発時間を短縮できますが、各プラットフォーム固有の要素には追加の設定が必要です。

View Protocolとビューの本体

SwiftUIでは、各画面はViewプロトコルを実装する構造体であり、唯一の要件はsome View型の計算プロパティbodyです。someキーワード(不透明型)は具体的なビューの型を隠し、SwiftUIがレンダリングを最適化できるようにします。body内で、開発者はViewBuilderを使用して既製のコンポーネント(Text、Image、Button、List)を組み合わせ、複数のビューを1つにまとめます。

swift
struct GreetingView: View {
    let name: String

    var var body: some View {
        VStack {
            Text("こんにちは、\(name)!")
                .font(.title)
                .foregroundColor(.blue)
            Image(systemName: "hand.wave")
                .imageScale(.large)
        }
        .padding()
    }
}

例では、VStack(垂直スタック)にTextとImageが含まれています。nameの値は構造体のイニシャライザを通じて渡されます。これがSwiftUIで外部DIコンテナなしでDI(依存性注入)が機能する仕組みです。各修飾子は、元の値を変更せずに変更を適用した新しいビューを返します。これは値型の不変性のおかげで可能です。

ViewBuilderと条件分岐

ViewBuilder@resultBuilderで注釈されたresult builderで、最大10個のビューを1つにまとめます。body内では、追加のラッパーなしでif/else、switch、ForEachを使用できます。ForEachはIdentifiable要素で動作し、挿入/削除時の正しいアニメーションのために各ビューに一意のIDが割り当てられます。

状態管理:@State、@Binding、@ObservedObject

SwiftUIでは、状態が画面に表示されるコンテンツを決定します。状態が変化すると、SwiftUIは依存するビューのbodyを再作成し、差分アルゴリズムを使用して結果を前のものと比較します。状態の保存にはプロパティラッパーが使用され、それぞれがローカル状態、子ビューとの接続、外部データモデルといった特定のタスクを解決します。

swift
struct CounterView: View {
    @State private var count = 0

    var var body: some View {
        VStack {
            Text("カウンター:\(count)")
            Button("増加") {
                count += 1
            }
        }
    }
}

class UserViewModel: ObservableObject {
    @Published var name = ""
    @Published var age = 0
}

@StateはView構造体内にローカルの単純な値(Int、String、Bool)を格納します。SwiftUIは構造体からメモリを別のストレージに移動するため、Viewが値型であっても@Stateのプロパティを変更できます。@ObservableObject@Publishedプロパティを持つクラス用で、その変更が自動的にSwiftUIに再レンダリングの必要性を通知します。

@Bindingと親子接続

@Bindingは親ビューにあるデータソースとの双方向接続を作成します。親は$variable(投影値)を渡し、子はバインディングを通じて値を読み書きします。これにより、親に状態を保持しながら、テキスト入力やトグルを別のコンポーネントに移動できます。@Bindingがない場合、変更のたびに新しい値を上位に渡すコールバッククロージャが必要になります。

iOS 16以前は、SwiftUIのナビゲーションはNavigationView上に構築されていました。これはiPadで複雑な動作(分割ビュー、二重列)をするレガシーAPIです。iOS 16以降、AppleはNavigationStackを推奨しています。これは型安全なルートを備えた簡素化された代替手段です。開発者が可能なルートの列挙型を定義すると、NavigationStackがディープリンクとルートへの戻りをサポートして画面スタックを自動的に管理します。

swift
enum Route: Hashable {
    case detail(id: Int)
    case settings
}

struct ContentView: View {
    var var body: some View {
        NavigationStack {
            List {
                NavigationLink("詳細画面",
                               value: Route.detail(id: 42))
                NavigationLink("設定",
                               value: Route.settings)
            }
            .navigationDestination(for: Route.self) { route in
                switch route {
                case .detail(let id): DetailView(id: id)
                case .settings: SettingsView()
                }
            }
        }
    }
}

Hashableに準拠したルートは、パラメータを渡すために任意のデータ型を使用できます。navigationDestination(for:destination:)はルート型をターゲットビューに関連付けます。UIKitナビゲーションに対する利点は、新しいルートを追加するときに再レンダリングが不要なことです。列挙型にケースを追加し、スイッチにハンドラを追加するだけです。ディープリンクはNavigationStackのprocessDeepLinkを通じて処理されます。

プログラムによるナビゲーション

プログラムによる遷移(ログイン後、タイマー後、サーバー応答後)には、NavigationLinkイニシャライザとともに@Stateを使用します:NavigationLink(isActive: $isActive)。isActive = trueに設定すると、ユーザーのタッチなしで遷移が実行されます。別の方法として、NavigationStackで$path配列をバインドします:$path.append(Route.detail(id: 1))

View Modifier — 外観のカスタマイズ

Modifierは、ビューの変更されたコピーを返すメソッドです。既存のビューを変更してプロパティを設定するUIKitとは異なり、SwiftUIは変更を適用した新しい値を作成します。修飾子の連鎖(チェイニング)により、フォント→パディング→色→影→ジェスチャーという順次の変換から最終的なインターフェースが構築されます。

Appleは200以上の組み込み修飾子を提供しています。最も一般的なもの:.font().foregroundColor().padding().background().cornerRadius().shadow().opacity().offset()。修飾子の順序は重要です:.padding()の前に.background()を置くとパディングを含む領域が塗りつぶされ、後に置くと内側の領域のみが塗りつぶされます。カスタム修飾子はViewModifierプロトコルを通じて作成されます。

条件付き修飾子とアニメーション

修飾子は三項演算子を使用して条件付きで適用できます:.foregroundColor(isError ? .red : .primary)。アニメーションには.animation(.easeInOut, value: state)を使用します。アニメーション修飾子は特定の状態プロパティに結び付けられます。このプロパティが変更されると、SwiftUIは古い値と新しい値の間の遷移をアニメーション化します。アニメーションはopacity、offset、scale、rotation、サイズ、色で機能し、各プロパティには対応するAnimatableParameterがあります。

カスタムアニメーションには、.transition(出現/消滅)と.matchedGeometryEffect(2つのコンテナ間の要素のスムーズな遷移)が利用できます。後者はリストのヒーローアニメーションに使用され、リストセルのアイコンが詳細画面で大きな画像にスムーズに変化します。

SwiftUI vs UIKit:アプローチの比較

SwiftUIとUIKitの選択は、iOS開発者にとって最初のジレンマの1つです。両方のフレームワークはAppleにサポートされていますが、インターフェース構築の問題を根本的に異なる方法で解決します。SwiftUIは宣言的に、UIKitは命令的に。その違いは、状態管理、ナビゲーション、パフォーマンス、互換性に現れます。

側面SwiftUIUIKit
アプローチ宣言型:何を表示するか命令型:どのように構築するか
状態Property Wrappers、自動再レンダリング手動:reloadData、setNeedsLayout
UIコードコンパクト、修飾子チェーン冗長、NSCoder/Storyboard/制約
パフォーマンスiOS 17+で高い、差分アルゴリズムiOS 12–16でピーク、直接制御
最小バージョンiOS 15+(完全サポート)iOS 2+(全バージョン)

最小iOS 17バージョンの新しいプロジェクトでは、AppleはSwiftUIを主要フレームワークとして推奨しています。UIKitは、レンダリングの細かい制御(カスタムUICollectionViewLayout、複雑なCAAnimationシーン)やiOS 12–14のサポートが必要なインターフェースに引き続き必要です。多くのプロジェクトではハイブリッドアプローチを採用しています。UIHostingControllerを介してSwiftUIをUIKitアプリに埋め込み、UIViewRepresentableを使用してSwiftUI階層内でUIKitコンポーネントを利用します。

よくある質問

同じプロジェクトでSwiftUIとUIKitを併用できますか?

はい、UIHostingController(SwiftUI in UIKit)とUIViewRepresentable(UIKit in SwiftUI)を通じて可能です。これは移行時に一般的なハイブリッドアプローチです。

SwiftUIプロジェクトはどのiOSバージョンから始めるべきですか?

iOS 17は完全な機能を提供します:NavigationStack、Observation framework、Swift Charts。iOS 15はプロダクションの最小基準です。

SwiftUIがインターフェースを更新しないことがあるのはなぜですか?

最も一般的な原因は、バックグラウンドスレッドで@Publishedプロパティを変更することです。ObservableObjectはmain actorで変更を送信する必要があります:@MainActor class ViewModel

SwiftUIでボタン押下のデバウンスを処理するには?

Combineを通じて.debounceを使用します:Button.publisher(for: .tap) .debounce(for: .seconds(0.3), scheduler: RunLoop.main)

SwiftUIはカスタムジェスチャーをサポートしていますか?

はい、Gesture修飾子を通じてサポートしています:DragGesture、LongPressGesture、MagnificationGesture、RotationGesture。.simultaneousGesture()と.sequenced()を使用して組み合わせます。

まとめ

  • SwiftUIはAppleの宣言型フレームワークで、インターフェースは状態管理のためのプロパティラッパーを備えたView構造体の合成として記述されます。
  • View Protocolと計算プロパティbodyは、あらゆるビューの単一のエントリポイントです。ViewBuilderは追加コンテナなしで最大10個のビューを1つにまとめます。
  • @State@Binding@ObservedObjectは、ローカル状態、親子接続、外部モデルのすべてのデータ管理シナリオをカバーします。
  • NavigationStackは型安全な列挙型ルートでNavigationViewを置き換え、ディープリンクとプログラムによるナビゲーションのサポートを追加しました。
  • ModifierはSwiftUIの重要なパターンで、継承なしで呼び出しチェーンを通じてビューの外観をカスタマイズできます。
  • SwiftUIとUIKitはUIHostingControllerとUIViewRepresentableを通じて共存し、段階的なプロジェクト移行を可能にします。
  • iOS 17+の場合、AppleはSwiftUIを主要フレームワークとして推奨しています。UIKitは複雑なカスタムインターフェースと古いバージョンのサポートに残ります。

ターンキー方式のモバイルアプリケーションを開発します

IT Sectrは2017年からスタートアップや企業向けにiOS・Androidアプリケーションを開発しています。私たちがご相談に乗り、最適なソリューションをご提案します。

プロジェクトについて相談

こちらもお読みください