SwiftUI iOS 앱 개발 기초 가이드 — 상태 관리와 iOS 버전별 API

모바일 2026년 8월 5일  ·  2026. 10. 30 업데이트  ·  junetapa  ·  약 12분

SwiftUI는 2019년 iOS 13과 함께 공개된 Apple의 선언형 UI 프레임워크다. 화면을 «어떻게 바꿀지»의 절차가 아니라 «지금 상태에서 어떤 모습이어야 하는지»를 적으면, 프레임워크가 상태 변화와 화면 갱신을 잇는다. 이 편의에는 조건이 붙는다. 어떤 API를 쓸 수 있는지는 최소 배포 버전이 정하고, 어떤 뷰가 다시 그려지는지는 상태를 담는 방식이 정한다. 이 글은 Xcode 27(iOS 27 SDK) 시점의 Apple 공식 문서를 기준으로, 처음 시작할 때 정해야 할 것과 자주 걸리는 지점을 정리했다.

선언형 UI의 기본 구조

View 프로토콜과 body

SwiftUI의 화면 요소는 View 프로토콜을 따르는 구조체다. 클래스가 아니라 값 타입이고, 필요한 것은 body 계산 프로퍼티 하나뿐이다. body에는 결과 빌더가 붙어 있어 여러 뷰를 나열하면 하나의 합성 타입으로 묶인다. 중첩이 깊어질수록 이 타입이 길어지고 타입 검사 부담도 커지므로, body 하나에 수십 줄을 몰아넣으면 빌드가 느려지거나 «타입 추론에 실패했다»는 오류를 만나기 쉽다. 대응은 단순하다. 뷰를 잘게 나누고, 반복되는 묶음은 별도 타입으로 뺀다.

import SwiftUI

@main
struct CounterApp: App {
    var body: some Scene {
        WindowGroup {
            CounterView()
        }
    }
}

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

    var body: some View {
        VStack(spacing: 12) {
            Text("눌린 횟수: \(count)")
            Button("하나 더") { count += 1 }
        }
        .padding()
    }
}

앱 진입점과 Scene

iOS 14부터 App 프로토콜과 @main으로 앱 진입점 전체를 SwiftUI로 쓸 수 있다. 위 예제처럼 WindowGroup 같은 Scene이 최상위 그릇이 되고, 그 안에 루트 뷰를 넣는다. iOS 13 시절 방식은 UIHostingController를 UIKit 앱 델리게이트에 얹는 형태였다. 지금 App Store는 배포 대상 iOS 13 이상을 요구하므로(아래 3절), 새 프로젝트라면 처음부터 App 프로토콜로 시작하면 된다.

레이아웃 협상 규칙

SwiftUI 레이아웃은 세 단계로 움직인다. 부모가 크기를 제안하고, 자식이 그 제안 안에서 자기 크기를 스스로 정하고, 부모가 그 결과를 배치한다. 자식이 부모의 제안을 꼭 따르지는 않는다는 점이 핵심이다. frame 수정자를 걸었는데 뜻대로 안 되는 경우 대부분은 이 순서를 오해한 결과다. 제약을 선언하고 해결기에 맡기는 오토레이아웃과는 출발점이 다르다.

부모가 크기를 제안하고 자식이 정하며 부모가 배치하는 스위프트유아이 레이아웃 협상 과정을 나타낸 도해
부모가 강제하지 않고 «제안»한다는 점이 UIKit 과 가장 다른 대목이다.

상태 관리 — 누가 값을 소유하는가

상태 관련 실수는 대부분 «이 값을 누가 소유하는가»를 잘못 정한 데서 나온다. 값을 직접 가진 뷰는 @State, 위에서 받은 값을 읽고 쓰기만 하는 뷰는 @Binding을 쓴다. 참조 타입(모델 클래스)을 다룰 때는 iOS 17부터 들어온 Observation 방식이 기본이 됐다.

Observation 방식 — @Observable

Apple 문서는 iOS 17·iPadOS 17·macOS 14·tvOS 17·watchOS 10부터 SwiftUI가 Observation을 지원한다고 적는다. 모델 클래스에 @Observable 매크로를 붙이면 ObservableObject·@Published 없이 일반 프로퍼티만으로 변화가 추적된다. 문서 설명대로 SwiftUI는 body가 직접 읽은 프로퍼티가 바뀔 때만 그 뷰를 갱신하고, 읽지 않은 프로퍼티가 바뀌어도 갱신하지 않는다. 화면 하나가 모델의 모든 변화에 다시 그려지던 문제가 여기서 줄어든다.

import Observation

@Observable
final class CartModel {
    var items: [String] = []
    var coupon = ""
}

struct CartScreen: View {
    @State private var cart = CartModel()      // 이 뷰가 소유
    var body: some View {
        CouponField(cart: cart)
            .environment(cart)                 // 아래 뷰들에 전달
    }
}

struct CouponField: View {
    @Bindable var cart: CartModel              // 바인딩이 필요할 때만
    var body: some View {
        TextField("쿠폰", text: $cart.coupon)
    }
}

struct CartCount: View {
    @Environment(CartModel.self) private var cart
    var body: some View { Text("\(cart.items.count)개") }
}

예전 방식과의 대응

예전(ObservableObject)Observation 방식문서 설명
@StateObject@State모델 타입을 바꾼 뒤 StateObject를 State로 바꾼다
@ObservedObject일반 프로퍼티 · 바인딩이 필요하면 @BindableObservation에서는 이 래퍼가 필요 없다
@EnvironmentObject@Environment(타입.self) + .environment(모델)Environment 래퍼를 쓴다

iOS 16 이하를 지원해야 한다면 예전 방식을 써야 한다. 이때 가장 흔한 실수는 객체를 만드는 자리에 @ObservedObject를 쓰는 것이다. @StateObject와 달리 뷰가 다시 평가될 때 인스턴스를 지켜 주지 않아 상태가 처음으로 돌아간다. 화면이 이유 없이 초기화된다면 이 자리부터 본다. @EnvironmentObject는 주입하지 않은 채 접근하면 실행 중에 멈추므로, 미리보기나 시험용 뷰에서 주입을 빠뜨리지 않았는지도 확인한다.

시작 전 확인할 제약 — 버전·도구·배포

최소 배포 버전이 곧 API 범위

SwiftUI를 배울 때 가장 자주 부딪히는 벽은 문법이 아니라 가용성이다. 튜토리얼 코드가 그대로 빌드되지 않는다면 대개 그 API의 최소 버전이 프로젝트 설정보다 높기 때문이다. 주요 API가 들어온 시점은 다음과 같다(Apple 문서의 가용성 표시 기준).

아이오에스 13부터 17까지 버전별로 사용할 수 있는 스위프트유아이 기능을 정리한 도해
최소 배포 버전이 곧 쓸 수 있는 API 범위다 — 문법보다 이 제약이 먼저 걸린다.
기능최소 iOS 버전비고
기본 뷰(List, TabView, NavigationView)iOS 13NavigationView는 지금 사용 중단 표시
App 프로토콜 기반 수명 주기, @StateObjectiOS 14iOS 13은 UIHostingController 필요
.task 수정자, .searchableiOS 15async/await 연동
NavigationStack, NavigationSplitView, Layout 프로토콜, Swift ChartsiOS 16내비게이션 모델 바뀜
@Observable(Observation), SwiftDataiOS 17상태·저장 방식 바뀜

내비게이션은 특히 조심한다. Apple 문서는 NavigationView에 사용 중단(deprecated) 표시를 달고 NavigationStack과 NavigationSplitView를 쓰라고 안내한다. iOS 15 이하까지 지원하면 신형 API를 쓸 수 없어 if #available로 두 경로를 갈라 관리하고 각각 따로 확인해야 한다. 지원 범위를 한 단계 낮추는 결정이 코드량과 확인 범위를 함께 늘린다는 뜻이다.

개발 환경 — Xcode 27(2026-10-30 확인)

Xcode필요한 macOSiOS SDKSwift
Xcode 27.2 RCmacOS Tahoe 26.6 이상iOS 27.2Swift 6.4 컴파일러
Xcode 27.1macOS Tahoe 26.6 이상iOS 27.1Swift 6.4 컴파일러
Xcode 27macOS Tahoe 26.6 이상iOS 27Swift 6.4 컴파일러

Xcode는 macOS에서만 돌고, 미리보기와 시뮬레이터도 여기에 묶여 있다. 쓸 수 있는 SDK와 시뮬레이터 런타임은 설치한 Xcode 판이 정하므로, 새 OS의 API를 쓰려면 Xcode부터 올린다. Apple 지원 페이지 기준으로 Xcode 27 계열은 Swift 6·5·4.2·4 언어 모드를 모두 지원하므로, 기존 프로젝트를 올릴 때 언어 모드를 한꺼번에 바꿀 필요는 없다.

App Store에 올리려면

스토어 등록 뒤 검색 노출과 상세 페이지를 다듬는 일은 앱 스토어 최적화(ASO) 전략 가이드에 따로 정리했다.

2027 릴리스에서 바뀐 것

Apple의 «What's new in SwiftUI» 페이지는 Xcode 27과 함께 나온 2027 릴리스의 변화를 아래처럼 묶는다. 페이지에는 OS 판이 따로 적혀 있지 않으므로, 쓰기 전에 각 심볼 문서의 가용성 표시를 확인한다.

갈래바뀐 것
상태State가 매크로가 되어, @State에 담은 클래스가 뷰 수명 동안 한 번만 늦게 초기화된다
빌드ViewBuilder가 ContentBuilder로 공개되고, 빌드 시간이 나아졌다고 설명
이미지AsyncImage가 기본으로 표준 HTTP 캐시를 쓰고, asyncImageURLSession으로 세부 조정
툴바visibilityPriority·toolbarOverflowMenu·topBarPinnedTrailing · 스크롤 때 내비게이션 바를 접는 toolbarMinimizeBehavior
목록 상호작용List·LazyVGrid 등에서 쓰는 순서 바꾸기 API(watchOS 첫 지원) · 아무 ScrollView에서 밀어서 동작을 쓰는 swipeActionsContainer
알림 창확인 대화상자와 알림이 시트처럼 항목 바인딩을 받음
문서 앱WritableDocument·ReadableDocument로 비동기·점진 저장과 진행률 보고

입문 단계에서 체감이 큰 것은 첫 줄이다. 예전에는 @State에 클래스를 넣으면 뷰가 다시 만들어질 때마다 초기화 코드가 불리는 점을 신경 써야 했는데, 새 매크로는 이를 뷰 수명당 한 번으로 묶는다. 다만 배포 대상이 그보다 낮다면 예전 동작을 기준으로 코드를 짠다.

UIKit 상호운용과 미리보기

UIKit을 감싸고, SwiftUI를 얹는다

SwiftUI가 모든 것을 대신하지는 않는다. 세밀한 텍스트 편집 제어, 일부 카메라·미디어 화면, 오래된 외부 UI 라이브러리는 여전히 UIKit 기반인 경우가 많다. UIViewRepresentable·UIViewControllerRepresentable로 UIKit 부품을 감싸 SwiftUI 안에 넣고, 반대로 UIHostingController로 SwiftUI 뷰를 UIKit 화면에 넣는다. 두 방향 통로가 공식 API로 있으니, 기존 앱을 한 번에 갈아엎지 않고 화면 단위로 옮길 수 있다.

미리보기가 멈추는 자리

Xcode 미리보기는 앱 전체를 실행하지 않고 해당 뷰만 따로 빌드해 그린다. 그래서 뷰가 앱 실행 때만 있는 값에 기대면 빌드는 되는데 미리보기만 실패한다. 네트워크 응답, 로그인 세션, 전역 싱글턴이 대표적이다. 뷰의 입력을 파라미터로 빼서 미리보기용 더미 데이터를 넣을 수 있게 하면 풀리고, 그 과정에서 뷰가 시험하기 쉬운 모양으로 정리된다.

미리보기가 성공해도 실기기와 다른 지점이 남는다. 글자 크기 조절(Dynamic Type), 다크 모드, 화면 회전, 저사양 기기의 스크롤은 미리보기가 보장하지 않는다. 특히 글자를 키우면 고정 높이를 준 레이아웃이 잘린다. 출시 전에 글자 크기 최대, 다크 모드, 좁은 화면 세 조합을 한 번씩 훑는 것을 기본 점검으로 둔다.

초반에 자주 걸리는 지점

SwiftUI, UIKit, 크로스플랫폼 비교

항목SwiftUIUIKit크로스플랫폼 계열
대상 플랫폼iOS·iPadOS·macOS·watchOS·tvOS·visionOSiOS·iPadOS 중심(Mac Catalyst)Apple 플랫폼 + Android 등
언어SwiftSwift·Objective-CDart·JavaScript·Kotlin 등
UI 작성 방식선언형, 상태 기반명령형, 뷰 계층 직접 조작대체로 선언형
새 OS 기능 대응OS SDK와 함께 제공OS SDK와 함께 제공브리지·플러그인 지원을 기다림
개발 환경macOS + Xcode 필수macOS + Xcode 필수iOS 빌드·배포 단계에 macOS + Xcode 필요

고르는 기준

스위프트유아이와 유아이킷, 크로스플랫폼 계열의 대상 플랫폼과 작성 방식, 새 기능 대응을 비교한 도해
새 OS 기능을 언제 쓸 수 있느냐가 셋을 가르는 가장 실무적인 차이다.

정리 — 시작 순서

SwiftUI 학습의 출발점은 문법이 아니라 두 가지 결정이다. 지원할 최소 iOS 버전, 그리고 각 상태를 누가 소유하는지. 이 둘이 정해지면 나머지 API 선택은 대체로 따라온다.

순서할 일확인
1배포 대상 iOS 버전 정하기(App Store 하한 iOS 13)쓰려는 API의 가용성 표시
2Xcode 최신판 설치(macOS Tahoe 26.6 이상)빌드 SDK가 스토어 요건(iOS 26 SDK 이상)을 넘는지
3상태 소유 정하기 — iOS 17 이상이면 @Observable + @Statebody가 읽는 프로퍼티만 갱신되는지
4내비게이션은 NavigationStack·NavigationSplitViewNavigationView를 새로 쓰지 않았는지
5UIKit이 필요한 부분만 감싸기Representable 범위가 화면 일부에 머무는지
6글자 크기 최대·다크 모드·좁은 화면 점검잘리는 레이아웃이 없는지

버전별 가용성과 동작 세부는 해마다 바뀌므로, 판단 근거는 Apple 개발자 문서의 해당 심볼 페이지에 표시된 가용성 정보에서 확인한다.

SwiftUI iOS 앱 개발 기초 가이드 대표 그림 — 왼쪽에 제목 글자가 있고, 오른쪽에 화면 카드들이 겹쳐 쌓인 스마트폰과 상태 값이 화면으로 이어지는 선, 단계별 버전 계단이 있는 장면
SwiftUI iOS 앱 개발 기초 가이드 — 상태 관리와 iOS 버전별 API.

자주 묻는 것

SwiftUI를 배우려면 어떤 iOS 버전을 기준으로 잡아야 하나요?

새 프로젝트라면 iOS 17 이상을 배포 대상으로 잡으면 @Observable과 SwiftData, NavigationStack을 분기 없이 쓸 수 있습니다. App Store는 2026년 9월 9일부터 iOS 13 이상을 대상으로 하도록 요구하므로 그보다 낮출 수는 없습니다.

@StateObject와 @ObservedObject는 이제 안 쓰나요?

iOS 17 이상이면 Apple 문서는 모델에 @Observable을 붙이고 StateObject 자리는 State로, 바인딩이 필요한 ObservedObject 자리는 Bindable로 바꾸라고 안내합니다. iOS 16 이하를 지원해야 하면 예전 방식을 계속 씁니다.

NavigationView를 계속 써도 되나요?

Apple 문서에서 NavigationView에는 사용 중단 표시가 붙어 있고 NavigationStack과 NavigationSplitView를 쓰라고 안내합니다. 새로 만드는 화면은 두 신형 API로 시작하는 편이 낫습니다.

Windows PC로도 SwiftUI 앱을 만들 수 있나요?

Xcode는 macOS에서만 실행되고, 지금 Xcode 27은 macOS Tahoe 26.6 이상이 필요합니다. App Store에 올리려면 Xcode 26 이상과 iOS 26 SDK 이상에서 빌드해야 하므로 Mac이 필요합니다.

참고 자료

  1. Apple Developer Documentation. Migrating from the Observable Object protocol to the Observable macro — iOS 17 등 지원 시점, StateObject→State, ObservedObject→Bindable, EnvironmentObject→Environment, body가 읽은 프로퍼티만 갱신(2026-10-30 확인). developer.apple.com
  2. Apple Developer Documentation. NavigationView — iOS 13 도입, 사용 중단 표시, NavigationStack·NavigationSplitView 안내(2026-10-30 확인). developer.apple.com
  3. Apple Developer. Xcode support — Xcode 27·27.1·27.2 RC, macOS Tahoe 26.6 이상, iOS 27 SDK, Swift 6.4, 언어 모드(2026-10-30 확인). developer.apple.com
  4. Apple Developer News. Upcoming requirements — 2026-04-28 Xcode 26·iOS 26 SDK 빌드, 2026-09-09 iOS 13 이상 대상(2026-10-30 확인). developer.apple.com
  5. Apple Developer. What's new in SwiftUI — 2027 릴리스: State 매크로, ContentBuilder, AsyncImage 캐시, 툴바·순서 바꾸기·문서 API(2026-10-30 확인). developer.apple.com
  6. Apple Developer Program. What's included — 멤버십 1년 99 USD·면제 대상(2026-10-30 확인). developer.apple.com
SwiftUI iOS Apple 개발 모바일 junetapa
junetapa(박준철)
개발자가 아니라 쓰는 사람. IT 현장 27년의 기준으로 도구를 고르고 기록한다.
Share Twitter Facebook URL 복사