모바일 개발에서의 SwiftUI: 개념, 핵심 원리 및 작동 방식

저자: IT Sectr 게시일: 2026-07-02 읽는 시간: 10 분
SwiftUI는 모든 플랫폼에서 인터페이스를 구축하기 위한 Apple의 선언적 프레임워크입니다. Apple SwiftUI Docs (2025)에 따르면, App Store의 새로운 앱 중 70%가 SwiftUI를 사용합니다. SwiftUI의 핵심 개념 이해 — View Protocol, @ViewBuilder, NavigationStack — 현대 iOS 개발의 기초입니다.

핵심 요점

  • View Protocol — var body: some View. 각 View는 View 프로토콜을 준수하는 구조체입니다. body는 UI 설명입니다.
  • @ViewBuilder — 컨테이너에서 여러 View를 위한 Result Builder입니다. body 내에서 if/else, switch, ForEach.
  • NavigationStack (iOS 16+) — 데이터 기반 내비게이션. 경로 기반, 딥 링킹. NavigationView를 대체합니다.
  • @StateObject — 객체 소유권. @ObservedObject — 관찰. @EnvironmentObject — 환경.
  • @FocusState — 포커스 관리. .task{}, .onAppear{} — 라이프사이클. PreviewProvider — 미리보기.

기초 (View Protocol, body, some View, @ViewBuilder)

View Protocol은 SwiftUI의 핵심 프로토콜입니다. 단일 속성만 필요합니다: var body: some View. body는 UI 설명을 반환하는 computed property입니다. SwiftUI는 상태가 변경될 때마다 body를 호출하고 GPU에서 결과를 렌더링합니다.

@ViewBuilder

@ViewBuilder는 View용 Result Builder입니다. return과 TupleView 없이 클로저 내에 여러 View를 작성할 수 있습니다. if/else, switch, ForEach를 지원합니다. 모든 컨테이너(VStack, HStack, ZStack, Group)는 @ViewBuilder를 사용합니다. 레이아웃 없이 그룹화하려면 Group { … }을 사용합니다. some View는 Opaque Type입니다. 컴파일러는 구체적인 View 유형(Text, Button, VStack 등)을 알고 있지만 외부적으로는 some View로 반환합니다. 이를 통해 시그니처를 변경하지 않고 body 유형을 변경할 수 있습니다. ViewModifier — View 수정자: .font(), .padding(), .background(). ViewModifier 프로토콜과 .modifier()를 통한 사용자 정의 수정자.

swift
// @ViewBuilder 및 NavigationStack을 사용한 View 예제
struct ContentView: View {
    @State private var items = ["Item 1", "Item 2"]

    var body: some View {
        NavigationStack {
            List(items, id: .self) { item in
                NavigationLink(item) {
                    DetailView(item: item)
                }
            }
            .navigationTitle("Items")
            .toolbar {
                ToolbarItem(placement: .navigationBarTrailing) {
                    Button("Add") {
                        items.append("New Item")
                    }
                }
            }
        }
    }
}

// @StateObject를 사용한 DetailView
struct DetailView: View {
    let item: String
    @StateObject private var viewModel = DetailViewModel()

    var body: some View {
        Text(item)
            .task {
                await viewModel.loadDetails(for: item)
            }
    }
}

수정자와 컨테이너 (ViewModifier, NavigationStack, List, Form)

NavigationStack (iOS 16+) — 데이터 기반 내비게이션. 경로(해시 가능한 값의 배열)를 받아 navigationDestination을 통해 대상을 표시합니다. 대상 뷰가 있는 NavigationLink를 대체합니다. NavigationLink — 스택을 탐색하는 버튼. List — 섹션, 스와이프, 삭제 및 드래그 앤 드롭을 지원하는 세로 목록. Form — 설정에 특화된 List: 섹션, 피커, 토글, 텍스트 필드. Section — 헤더와 푸터가 있는 List/Form의 그룹화. ViewModifier — 스타일 재사용을 위한 사용자 정의 수정자. .modifier(CustomModifier()) — 적용.

List와 Form 상세

List는 SwiftUI에서 UITableView에 해당합니다. .onDelete, .onMove, .refreshable을 지원합니다. SwipeActions — .swipeActions { Button("삭제", role: .destructive) { } }. Form — 설정에 최적화: DatePicker, Toggle, Stepper, Picker. 헤더/푸터가 있는 Section — 그룹화용. OutlineGroup — 계층적 목록(섹션이 있는 UITableView에 해당). DisclosureGroup — 접을 수 있는 섹션. IT Sectr은 데이터에는 List, 설정에는 Form을 권장합니다.

PreviewProvider — Xcode Canvas에서 미리보기 위한 프로토콜. Canvas — 대화형 SwiftUI 미리보기(@main 및 Swift 5.9+ 필요). @ScaledMetric — Dynamic Type에 따라 확장되는 적응형 크기.

상태 관리 (@StateObject, @ObservedObject, @EnvironmentObject, @FocusState)

Property Wrappers는 SwiftUI에서 상태 관리의 기초입니다. @State — 로컬 상태(값 유형). @Binding — 부모 상태 연결. @StateObject — ObservableObject를 생성합니다. SwiftUI가 객체의 라이프사이클을 관리합니다. @ObservedObject — 외부 ObservableObject를 관찰합니다. @EnvironmentObject — 환경의 객체(.environmentObject()를 통한 의존성 주입). @Environment — 시스템 값(.colorScheme, .locale). @AppStorage — UserDefaults. @FetchRequest — Core Data 쿼리. @FocusState — 입력 포커스.

래퍼 목적 소유권
@State로컬 상태(값 유형)View 소유
@Binding부모 상태 연결부모 소유
@StateObjectObservableObject 생성View 소유
@ObservedObject외부 객체 관찰외부 소유자
@EnvironmentObject환경의 객체조상 소유
@Environment시스템 값시스템
@AppStorageUserDefaultsUserDefaults
@FocusState입력 포커스View 소유

@StateObject vs @ObservedObject: @StateObject는 객체를 생성하고, @ObservedObject는 관찰합니다. 계층 구조에서 첫 모델 생성에는 @StateObject를, 하위 뷰에 전달할 때는 @ObservedObject를 사용합니다. @FocusState — 포커스 관리: .focused($field, equals: .email). 여러 필드에 enum 지원.

환경 값과 DI

@Environment — 시스템 값: colorScheme, locale, sizeCategory, layoutDirection, managedObjectContext. 사용자 정의 환경 값(Custom Environment Values) — EnvironmentKey를 통한 사용자 정의 값. 의존성 주입에 사용: 명시적 매개변수 없이 서비스 전달. .environment() 수정자 — 계층 구조에 값 설정. @EnvironmentObject — .environmentObject()의 ObservableObject. 참조 유형을 전달한다는 점에서 @Environment와 다릅니다. IT Sectr은 시스템 값에는 @Environment, 서비스에는 @EnvironmentObject를 권장합니다.

라이프사이클 (.task, .onAppear, .onDisappear)

.task{} — 뷰 표시 시 비동기 작업. 사라질 때 자동 취소. async/await를 위해 .onAppear를 대체합니다. .onAppear{} — 표시 시 동기 작업. .onDisappear{} — 사라질 때 작업. .onChange(of:) — 값 변경에 반응. .onReceive(Publisher) — Combine 게시자에 반응. SwiftUI의 View 라이프사이클: init → onAppear → body(렌더링) → onDisappear. 상태 변경 시: body → diff → 재렌더링. IT Sectr은 비동기 로딩에는 .task, 분석에는 .onAppear를 권장합니다.

SwiftUI의 애니메이션

.animation() — 애니메이션 수정자. .transition() — 나타나기/사라지기 애니메이션. withAnimation — 명시적 상태 변경 애니메이션. matchedGeometryEffect — 다른 뷰 간 애니메이션(히어로 애니메이션). PhaseAnimator (iOS 17+) — enum 기반 다단계 애니메이션. KeyframeAnimator (iOS 17+) — 키프레임을 사용한 프레임별 애니메이션. SwiftUI 애니메이션은 Core Animation을 통해 GPU에서 실행됩니다. IT Sectr은 자연스러운 애니메이션에는 .spring(), 물리 효과에는 .interpolatingSpring을 권장합니다.

데이터 흐름 (Bindings, @Published, ObservableObject)

ObservableObject — @Published 속성이 있는 객체용 프로토콜. SwiftUI는 objectWillChange 게시자를 구독합니다. @Published — 속성 변경을 게시합니다. @StateObject — ObservableObject 생성, 라이프사이클 관리. @ObservedObject — 외부 관찰. Combine — 반응형 프로그래밍 프레임워크. @EnvironmentObject — 환경을 통한 DI. .environmentObject() 설정, @EnvironmentObject 읽기. MVVM — 표준 아키텍처: View (SwiftUI) — ViewModel (ObservableObject) — Model. IT Sectr은 주요 ViewModel에 MVVM + @StateObject를 권장합니다.

swift
class UserViewModel: ObservableObject {
    @Published var users: [User] = []
    @Published var isLoading = false

    func loadUsers() async {
        isLoading = true
        defer { isLoading = false }
        do {
            users = try await api.fetchUsers()
        } catch {
            print("오류: \(error)")
        }
    }
}

struct UsersView: View {
    @StateObject private var viewModel = UserViewModel()

    var body: some View {
        List(viewModel.users, id: \.id) { user in
            Text(user.name)
        }
        .task { await viewModel.loadUsers() }
        .overlay {
            if viewModel.isLoading { ProgressView() }
        }
    }
}

접근성 및 현지화

접근성 in SwiftUI: .accessibilityLabel(), .accessibilityHint(), .accessibilityValue(), .accessibilityAddTraits(). VoiceOver가 접근성 레이블을 읽습니다. Dynamic Type — @ScaledMetric, @DynamicProperty. 현지화: String(localized:) (SwiftUI + String Catalog). LocalizedStringKey — 자동 번역. 복수 규칙 — String Catalog를 통해 (one, few, many, other). 오른쪽에서 왼쪽(아랍어, 히브리어) — 자동 지원. .environment(.layoutDirection, .rightToLeft). IT Sectr은 모든 대화형 요소에 접근성 레이블을 권장합니다.

swift
struct AccessibleButton: View {
    let action: () -> Void

    var body: some View {
        Button(action: action) {
            Label("Settings", systemImage: "gear")
        }
        .accessibilityLabel("Open Settings")
        .accessibilityHint("Double tap to navigate to settings screen")
        .accessibilityAddTraits(.isButton)
    }
}

// Dynamic Type 지원
struct ScalableText: View {
    @ScaledMetric private var fontSize: CGFloat = 17

    var body: some View {
        Text("Hello, World!")
            .font(.system(size: fontSize))
    }
}

차트 및 시각화 (Swift Charts)

Swift Charts (iOS 16+) — 차트 구축을 위한 프레임워크. Chart { } — 기본 컨테이너. BarMark, LineMark, PointMark, AreaMark, RuleMark — 마크. 데이터용 ForEach. ChartAxis — 축 사용자 정의. .chartXAxis, .chartYAxis. ChartLegend — 범례. 보간 — catmullRom, linear, step. 애니메이션 — Chart용 .animation(). IT Sectr은 내장 차트에는 Swift Charts, 복잡한 차트에는 Charts(DGCharts)를 권장합니다.

swift
import Charts

struct MonthlySales: Identifiable {
    let id = UUID()
    let month: String
    let sales: Double
}

struct SalesChart: View {
    let data: [MonthlySales]

    var body: some View {
        Chart(data) { item in
            BarMark(
                x: .value("Month", item.month),
                y: .value("Sales", item.sales)
            )
            .foregroundStyle(.blue.gradient)
        }
        .chartXAxisLabel("Month")
        .chartYAxisLabel("Sales")
        .frame(height: 200)
        .padding()
    }
}

Swift Package Manager (SPM) — Apple의 의존성 관리자. Xcode에 통합. 지원: 바이너리 패키지, 리소스, 테스트, swift-6 엄격한 동시성. semver 태그로 GitHub를 통한 패키지 게시. SPM은 CocoaPods와 Carthage를 대체하는 Swift 의존성의 사실상 표준입니다. IT Sectr은 모든 새 프로젝트에 SPM을 권장합니다.

Swift Concurrency (async/await, TaskGroup, AsyncSequence) — async/await는 Swift 5.5+에 내장. Task — 비동기 단위. TaskGroup — 병렬 작업. AsyncSequence — 비동기 시퀀스(AsyncStream, AsyncAlgorithms). Task Local Values — Task의 컨텍스트 데이터. Swift Concurrency는 비동기 작업에서 Combine을 완전히 대체합니다.

자주 묻는 질문

SwiftUI에서 View Protocol이란?

View Protocol은 기본 프로토콜입니다. var body: some View가 필요합니다. body는 GPU에서 렌더링되는 UI 설명입니다.

@ViewBuilder란 무엇이며 왜 필요한가요?

@ViewBuilder는 여러 View를 위한 Result Builder입니다. 컨테이너 내에서 if/else, switch, ForEach를 허용합니다.

@StateObject와 @ObservedObject의 차이점은?

@StateObject는 객체를 생성합니다. @ObservedObject는 기존 객체를 관찰합니다. 계층 구조에서 첫 생성에는 @StateObject.

iOS 16+의 NavigationStack이란?

NavigationStack — 데이터 기반 내비게이션. 경로 기반, 딥 링킹. NavigationView를 대체합니다.

SwiftUI에서 @FocusState는 어떻게 작동하나요?

@FocusState — 입력 포커스 관리. .focused() 수정자. 여러 필드에 enum 지원.

요약

  • View Protocol — var body: some View. SwiftUI의 기초. 각 View는 구조체입니다.
  • @ViewBuilder — 여러 View를 위한 선언적 구문. body 내 if/else, ForEach.
  • NavigationStack (iOS 16+) — 최신 내비게이션. 데이터 기반, 경로 기반.
  • @StateObject — 모델 소유권. @ObservedObject — 관찰. @EnvironmentObject — DI.
  • @FocusState — 포커스 관리. 폼 및 여러 입력 필드에 유용.
  • .task{} — 자동 취소 기능이 있는 비동기 작업. .onAppear{} — 동기.
  • PreviewProvider 및 Canvas — Xcode에서 미리보기. @ScaledMetric — 적응형 크기.

턴키 방식의 모바일 애플리케이션을 개발해 드립니다

IT Sectr는 2017년부터 스타트업과 기업을 위한 iOS 및 Android 애플리케이션을 만듭니다. 저희가 상담해 드리고 최적의 솔루션을 제안하겠습니다.

프로젝트 논의