SwiftUIは、Appleエコシステムのすべてのプラットフォーム向けにユーザーインターフェースを構築するための宣言型フレームワークです。手順を命令的に記述する代わりに、開発者はインターフェースの見た目を宣言し、SwiftUIがレンダリングと更新を管理します。Apple Developer Documentation(2025)によると、SwiftUIはiOS 15+、iPadOS 15+、macOS 12+、watchOS 8+、tvOS 15+をサポートし、すべてのインターフェースコンポーネントの基本構成要素としてView Protocolを使用します。
重要なポイント
bodyプロパティは、SwiftUIのUIコンポーネントの基盤であり、ビュー構成を通じて画面の説明を返します。SwiftUIは、2019年にAppleが新しいプロジェクトでUIKitを置き換えるために導入した宣言型フレームワークです。UIViewインスタンスを手動で作成して階層に追加する代わりに、開発者はViewプロトコルに準拠した構造体を通じてインターフェースを記述します。SwiftUIは現在の状態と新しい状態の差分を自動的に計算し、独自のレンダリングエンジンを使用して変更された部分のみを再レンダリングします。
フレームワークは値セマンティクス(クラスではなく構造体)を使用してSwiftで書かれており、UIコンポーネントを軽量かつスレッドセーフにします。Objective-CランタイムのためにUIViewControllerが200+バイトになる可能性があるUIKitとは異なり、SwiftUI Viewは数バイトの単純な構造体です。これはメモリが限られているwatchOSにとって特に重要です。
同じViewの記述がiPhone、iPad、Mac、Apple Watch、Apple TV、Apple Vision Proで動作します。SwiftUIはプラットフォームに合わせてインターフェースを適応させます:iOSではタッチジェスチャー、macOSではキーボードコンビネーション、watchOSではDigital Crownスクロール。これにより、複数のAppleプラットフォームでアプリをリリースする企業の開発時間を短縮できますが、各プラットフォーム固有の要素には追加の設定が必要です。
SwiftUIでは、各画面はViewプロトコルを実装する構造体であり、唯一の要件はsome View型の計算プロパティbodyです。someキーワード(不透明型)は具体的なビューの型を隠し、SwiftUIがレンダリングを最適化できるようにします。body内で、開発者はViewBuilderを使用して既製のコンポーネント(Text、Image、Button、List)を組み合わせ、複数のビューを1つにまとめます。
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は@resultBuilderで注釈されたresult builderで、最大10個のビューを1つにまとめます。body内では、追加のラッパーなしでif/else、switch、ForEachを使用できます。ForEachはIdentifiable要素で動作し、挿入/削除時の正しいアニメーションのために各ビューに一意のIDが割り当てられます。
SwiftUIでは、状態が画面に表示されるコンテンツを決定します。状態が変化すると、SwiftUIは依存するビューのbodyを再作成し、差分アルゴリズムを使用して結果を前のものと比較します。状態の保存にはプロパティラッパーが使用され、それぞれがローカル状態、子ビューとの接続、外部データモデルといった特定のタスクを解決します。
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は親ビューにあるデータソースとの双方向接続を作成します。親は$variable(投影値)を渡し、子はバインディングを通じて値を読み書きします。これにより、親に状態を保持しながら、テキスト入力やトグルを別のコンポーネントに移動できます。@Bindingがない場合、変更のたびに新しい値を上位に渡すコールバッククロージャが必要になります。
iOS 16以前は、SwiftUIのナビゲーションはNavigationView上に構築されていました。これはiPadで複雑な動作(分割ビュー、二重列)をするレガシーAPIです。iOS 16以降、AppleはNavigationStackを推奨しています。これは型安全なルートを備えた簡素化された代替手段です。開発者が可能なルートの列挙型を定義すると、NavigationStackがディープリンクとルートへの戻りをサポートして画面スタックを自動的に管理します。
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))。
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とUIKitの選択は、iOS開発者にとって最初のジレンマの1つです。両方のフレームワークはAppleにサポートされていますが、インターフェース構築の問題を根本的に異なる方法で解決します。SwiftUIは宣言的に、UIKitは命令的に。その違いは、状態管理、ナビゲーション、パフォーマンス、互換性に現れます。
| 側面 | SwiftUI | UIKit |
|---|---|---|
| アプローチ | 宣言型:何を表示するか | 命令型:どのように構築するか |
| 状態 | 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コンポーネントを利用します。
よくある質問
はい、UIHostingController(SwiftUI in UIKit)とUIViewRepresentable(UIKit in SwiftUI)を通じて可能です。これは移行時に一般的なハイブリッドアプローチです。
iOS 17は完全な機能を提供します:NavigationStack、Observation framework、Swift Charts。iOS 15はプロダクションの最小基準です。
最も一般的な原因は、バックグラウンドスレッドで@Publishedプロパティを変更することです。ObservableObjectはmain actorで変更を送信する必要があります:@MainActor class ViewModel。
Combineを通じて.debounceを使用します:Button.publisher(for: .tap) .debounce(for: .seconds(0.3), scheduler: RunLoop.main)。
はい、Gesture修飾子を通じてサポートしています:DragGesture、LongPressGesture、MagnificationGesture、RotationGesture。.simultaneousGesture()と.sequenced()を使用して組み合わせます。
まとめ
ターンキー方式のモバイルアプリケーションを開発します
IT Sectrは2017年からスタートアップや企業向けにiOS・Androidアプリケーションを開発しています。私たちがご相談に乗り、最適なソリューションをご提案します。