핵심 요점
View Protocol은 SwiftUI의 핵심 프로토콜입니다. 단일 속성만 필요합니다: var body: some View. body는 UI 설명을 반환하는 computed property입니다. SwiftUI는 상태가 변경될 때마다 body를 호출하고 GPU에서 결과를 렌더링합니다.
@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()를 통한 사용자 정의 수정자.
// @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)
}
}
}NavigationStack (iOS 16+) — 데이터 기반 내비게이션. 경로(해시 가능한 값의 배열)를 받아 navigationDestination을 통해 대상을 표시합니다. 대상 뷰가 있는 NavigationLink를 대체합니다. NavigationLink — 스택을 탐색하는 버튼. List — 섹션, 스와이프, 삭제 및 드래그 앤 드롭을 지원하는 세로 목록. Form — 설정에 특화된 List: 섹션, 피커, 토글, 텍스트 필드. Section — 헤더와 푸터가 있는 List/Form의 그룹화. ViewModifier — 스타일 재사용을 위한 사용자 정의 수정자. .modifier(CustomModifier()) — 적용.
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에 따라 확장되는 적응형 크기.
Property Wrappers는 SwiftUI에서 상태 관리의 기초입니다. @State — 로컬 상태(값 유형). @Binding — 부모 상태 연결. @StateObject — ObservableObject를 생성합니다. SwiftUI가 객체의 라이프사이클을 관리합니다. @ObservedObject — 외부 ObservableObject를 관찰합니다. @EnvironmentObject — 환경의 객체(.environmentObject()를 통한 의존성 주입). @Environment — 시스템 값(.colorScheme, .locale). @AppStorage — UserDefaults. @FetchRequest — Core Data 쿼리. @FocusState — 입력 포커스.
| 래퍼 | 목적 | 소유권 |
|---|---|---|
| @State | 로컬 상태(값 유형) | View 소유 |
| @Binding | 부모 상태 연결 | 부모 소유 |
| @StateObject | ObservableObject 생성 | View 소유 |
| @ObservedObject | 외부 객체 관찰 | 외부 소유자 |
| @EnvironmentObject | 환경의 객체 | 조상 소유 |
| @Environment | 시스템 값 | 시스템 |
| @AppStorage | UserDefaults | UserDefaults |
| @FocusState | 입력 포커스 | View 소유 |
@StateObject vs @ObservedObject: @StateObject는 객체를 생성하고, @ObservedObject는 관찰합니다. 계층 구조에서 첫 모델 생성에는 @StateObject를, 하위 뷰에 전달할 때는 @ObservedObject를 사용합니다. @FocusState — 포커스 관리: .focused($field, equals: .email). 여러 필드에 enum 지원.
@Environment — 시스템 값: colorScheme, locale, sizeCategory, layoutDirection, managedObjectContext. 사용자 정의 환경 값(Custom Environment Values) — EnvironmentKey를 통한 사용자 정의 값. 의존성 주입에 사용: 명시적 매개변수 없이 서비스 전달. .environment() 수정자 — 계층 구조에 값 설정. @EnvironmentObject — .environmentObject()의 ObservableObject. 참조 유형을 전달한다는 점에서 @Environment와 다릅니다. IT Sectr은 시스템 값에는 @Environment, 서비스에는 @EnvironmentObject를 권장합니다.
.task{} — 뷰 표시 시 비동기 작업. 사라질 때 자동 취소. async/await를 위해 .onAppear를 대체합니다. .onAppear{} — 표시 시 동기 작업. .onDisappear{} — 사라질 때 작업. .onChange(of:) — 값 변경에 반응. .onReceive(Publisher) — Combine 게시자에 반응. SwiftUI의 View 라이프사이클: init → onAppear → body(렌더링) → onDisappear. 상태 변경 시: body → diff → 재렌더링. IT Sectr은 비동기 로딩에는 .task, 분석에는 .onAppear를 권장합니다.
.animation() — 애니메이션 수정자. .transition() — 나타나기/사라지기 애니메이션. withAnimation — 명시적 상태 변경 애니메이션. matchedGeometryEffect — 다른 뷰 간 애니메이션(히어로 애니메이션). PhaseAnimator (iOS 17+) — enum 기반 다단계 애니메이션. KeyframeAnimator (iOS 17+) — 키프레임을 사용한 프레임별 애니메이션. SwiftUI 애니메이션은 Core Animation을 통해 GPU에서 실행됩니다. IT Sectr은 자연스러운 애니메이션에는 .spring(), 물리 효과에는 .interpolatingSpring을 권장합니다.
ObservableObject — @Published 속성이 있는 객체용 프로토콜. SwiftUI는 objectWillChange 게시자를 구독합니다. @Published — 속성 변경을 게시합니다. @StateObject — ObservableObject 생성, 라이프사이클 관리. @ObservedObject — 외부 관찰. Combine — 반응형 프로그래밍 프레임워크. @EnvironmentObject — 환경을 통한 DI. .environmentObject() 설정, @EnvironmentObject 읽기. MVVM — 표준 아키텍처: View (SwiftUI) — ViewModel (ObservableObject) — Model. IT Sectr은 주요 ViewModel에 MVVM + @StateObject를 권장합니다.
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은 모든 대화형 요소에 접근성 레이블을 권장합니다.
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 (iOS 16+) — 차트 구축을 위한 프레임워크. Chart { } — 기본 컨테이너. BarMark, LineMark, PointMark, AreaMark, RuleMark — 마크. 데이터용 ForEach. ChartAxis — 축 사용자 정의. .chartXAxis, .chartYAxis. ChartLegend — 범례. 보간 — catmullRom, linear, step. 애니메이션 — Chart용 .animation(). IT Sectr은 내장 차트에는 Swift Charts, 복잡한 차트에는 Charts(DGCharts)를 권장합니다.
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을 완전히 대체합니다.
자주 묻는 질문
View Protocol은 기본 프로토콜입니다. var body: some View가 필요합니다. body는 GPU에서 렌더링되는 UI 설명입니다.
@ViewBuilder는 여러 View를 위한 Result Builder입니다. 컨테이너 내에서 if/else, switch, ForEach를 허용합니다.
@StateObject는 객체를 생성합니다. @ObservedObject는 기존 객체를 관찰합니다. 계층 구조에서 첫 생성에는 @StateObject.
NavigationStack — 데이터 기반 내비게이션. 경로 기반, 딥 링킹. NavigationView를 대체합니다.
@FocusState — 입력 포커스 관리. .focused() 수정자. 여러 필드에 enum 지원.
요약
턴키 방식의 모바일 애플리케이션을 개발해 드립니다
IT Sectr는 2017년부터 스타트업과 기업을 위한 iOS 및 Android 애플리케이션을 만듭니다. 저희가 상담해 드리고 최적의 솔루션을 제안하겠습니다.