PreviewProvider는 Xcode Canvas에서 미리보기를 생성하기 위한 진입점을 정의하는 SwiftUI 프로토콜입니다. 프로토콜을 구현하면 개발자가 시뮬레이터를 실행하지 않고도 인터페이스를 볼 수 있어 레이아웃 단계에서 반복 작업을 가속화합니다. Apple Developer Documentation(2026)에 따르면 프로젝트가 Canvas를 사용하는 경우 PreviewProvider는 모든 SwiftUI View에 필수이며, 이것이 없으면 Canvas가 사용자 인터페이스를 표시하지 않습니다. SwiftUI에 관한 문서에서 자세히 알아보세요.
주요 내용
PreviewProvider는 Xcode Canvas에서 미리보기 콘텐츠를 생성하기 위한 계약을 정의하는 SwiftUI 프로토콜입니다. 프로토콜에는 하나의 필수 속성이 있습니다: previews(타입 some View). previews가 반환하는 모든 값은 Canvas에서 대화형 미리보기로 표시됩니다. PreviewProvider는 상속이 필요하지 않습니다 — extension에서 정적 구현으로 충분합니다.
아키텍처적으로 PreviewProvider는 SwiftUI 런타임의 일부가 아니라 순수한 개발 도구입니다. 프로토콜에는 @available(iOS 13.0, *) 속성이 표시되어 있으며 Xcode가 조건부 컴파일을 사용하여 프로덕션에서 미리보기 코드를 제외하므로 릴리스 빌드에서 컴파일되지 않습니다. 즉, PreviewProvider는 바이너리 크기나 애플리케이션 성능에 영향을 미치지 않습니다.
previews 속성은 PreviewProvider의 유일한 요구사항입니다. 단순한 Text부터 Group 및 ForEach를 포함한 복잡한 계층 구조까지 모든 View를 반환해야 합니다. Xcode는 반환된 View를 Canvas에서 렌더링하고 시스템 설정(테마, 크기, 폰트)을 적용합니다.
import SwiftUI
struct GreetingView: View {
let name: String
var body: some View {
Text("Hello, \(name)!")
.padding()
}
}
// PreviewProvider — static implementation
struct GreetingView_Previews: PreviewProvider {
static var previews: some View {
GreetingView(name: "World")
}
}
명명 규칙: Apple은 미리보기 구조체 이름을 {ViewName}_Previews로 지정할 것을 권장합니다. 컴파일러 요구사항은 아니지만 가독성과 프로젝트 탐색을 개선합니다. Xcode는 새 SwiftUI 파일을 생성할 때 자동으로 이 템플릿을 삽입합니다.
작동 메커니즘 PreviewProvider는 정적 디스패치를 기반으로 합니다. Xcode는 Debug 구성에 대해서만 PreviewProvider extension을 컴파일하고 Canvas 구축 과정에서 previews를 호출합니다. 코드가 변경될 때마다 Xcode는 변경된 PreviewProvider만 다시 컴파일하여 거의 즉각적인 미리보기 업데이트를 보장합니다.
SwiftUI는 시뮬레이터나 기기에서 미리보기와 최종 UI 간의 정확한 일치를 보장하지 않습니다 — Canvas는 단순화된 렌더링을 사용합니다. 지연이 있는 애니메이션이 올바르게 표시되지 않을 수 있으며 일부 UIKit 구성 요소(MapKit, WebView)는 추가 구성 없이 Canvas에서 렌더링되지 않습니다.
Group을 사용하면 하나의 View에 대한 여러 상태를 동시에 표시하여 다양한 구성을 레이아웃할 때 반복 작업을 가속화합니다. Group 내부의 각 미리보기는 독립적으로 렌더링됩니다.
struct ButtonView_Previews: PreviewProvider {
static var previews: some View {
Group {
ButtonView(title: "Primary", style: .primary)
.previewDisplayName("Primary")
ButtonView(title: "Disabled", style: .primary)
.disabled(true)
.previewDisplayName("Disabled")
ButtonView(title: "Secondary", style: .secondary)
.previewDisplayName("Secondary")
}
}
}
previewDisplayName은 Canvas의 각 미리보기에 레이블을 추가하여 여러 상태를 비교할 때 특히 유용합니다. Group의 미리보기 최대 개수는 제한이 없지만 6~8개를 초과하면 Canvas가 느려집니다.
Xcode는 미리보기 표시를 구성하기 위한 여러 수정자를 제공합니다. 주요 항목: previewDevice — 특정 기기를 에뮬레이트(iPhone 16 Pro, iPad Air, Apple Watch Ultra), previewLayout — 크기 설정(device, fixed, sizeThatFits). 이러한 수정자의 조합은 미리보기 환경을 완전히 제어할 수 있게 해줍니다.
previewDevice는 기기 이름이 포함된 문자열을 허용합니다(예: "iPhone 16 Pro" 또는 "iPad Pro 13-inch (M4)"). 사용 가능한 기기 목록은 Xcode에 설치된 시뮬레이터에 따라 다릅니다. 기기를 찾을 수 없으면 Canvas는 오류 없이 기본 기기에 미리보기를 표시합니다.
| 수정자 | 설명 | 예제 |
|---|---|---|
| previewDevice | 기기 에뮬레이션 | .previewDevice("iPhone 16 Pro") |
| previewLayout | 크기 모드 | .previewLayout(.sizeThatFits) |
| previewDisplayName | 미리보기 레이블 | .previewDisplayName("Dark Mode") |
| preferredColorScheme | 색상 구성표 | .preferredColorScheme(.dark) |
| dynamicTypeSize | 폰트 크기 | .dynamicTypeSize(.xxxLarge) |
일반적인 관행은 적응성을 확인하기 위해 하나의 View를 여러 기기에서 동시에 표시하는 것입니다. 이를 위해 기기 이름 배열과 함께 ForEach를 사용합니다.
struct AdaptiveView_Previews: PreviewProvider {
static var previews: some View {
ForEach(["iPhone SE (3rd generation)", "iPhone 16 Pro Max", "iPad Pro 13-inch (M4)"], id: \.self) { device in
AdaptiveView()
.previewDevice(.previewDevice(device))
.previewDisplayName(device)
}
}
}
실용적인 예제는 단순한 미리보기부터 실시간 데이터 및 UIKit 호환성을 포함한 복잡한 구성까지 PreviewProvider의 다양한 사용 시나리오를 보여줍니다.
모의 데이터는 View가 모델을 허용할 때 미리보기의 표준 패턴입니다. 실제 API 대신 테스트 데이터가 사용되어 애플리케이션을 실행하지 않고도 UI 상태를 시각적으로 확인할 수 있습니다.
struct UserProfileView: View {
let user: User
var body: some View {
VStack {
AsyncImage(url: user.avatarURL)
.clipShape(Circle())
Text(user.name)
.font(.title)
Text(user.bio)
.font(.body)
.foregroundColor(.secondary)
}
}
}
struct UserProfileView_Previews: PreviewProvider {
static var previews: some View {
UserProfileView(user: .mock)
.previewDisplayName("Profile")
UserProfileView(user: .mockLongName)
.previewDisplayName("Long Name")
}
}
UIKit 호환성 — PreviewProvider는 UIViewRepresentable로 래핑된 UIKit 구성 요소에서도 작동합니다. 이를 통해 전체 프로젝트를 마이그레이션하지 않고도 기존 UIKit 뷰를 SwiftUI Canvas에서 미리볼 수 있습니다.
struct MapViewRepresentable: UIViewRepresentable {
func makeUIView(context: Context) -> MKMapView {
MKMapView()
}
func updateUIView(_ uiView: MKMapView, context: Context) {
// Configure map
}
}
struct MapView_Previews: PreviewProvider {
static var previews: some View {
MapViewRepresentable()
}
}
Canvas는 PreviewProvider의 출력을 실시간으로 렌더링하는 Xcode의 비주얼 편집기입니다. PreviewProvider 구현이 없으면 Canvas는 비어 있습니다. Canvas와 PreviewProvider는 함께 작동합니다. PreviewProvider는 표시할 내용을 정의하고 Canvas는 위치와 방법을 정의합니다.
중요한 점은 Canvas는 미리보기 실행 환경이며 PreviewProvider의 대안이 아니라는 것입니다. 개발자가 Canvas를 열지 않더라도 Canvas 아이콘에 마우스를 올리면 팝업 미리보기를 통해 PreviewProvider를 빠른 코드 확인에 사용할 수 있습니다. WWDC 2024에 따르면 Apple은 단위 테스트 작성과 유사하게 모든 View에 PreviewProvider를 작성하는 것을 개발 표준으로 권장합니다.
| 구성 요소 | 역할 | 필수 여부 |
|---|---|---|
| PreviewProvider | 미리보기 콘텐츠 정의 | Canvas에 필수 |
| Canvas | 편집기에서 미리보기 렌더링 | 선택 사항(.preview 사용 가능) |
| SwiftUI View | UI 구성 요소 | 필수 |
권장 사항: 프로젝트의 모든 공개 View에 PreviewProvider를 작성하세요. 이는 새 개발자의 온보딩을 가속화하고 코드 검토를 간소화하며 전체 프로젝트를 빌드하지 않고도 시각적 변경 사항을 빠르게 확인할 수 있게 해줍니다.
문제 1: 미리보기가 업데이트되지 않음. Canvas가 코드 변경을 반영하지 않으면 원인은 일반적으로 DerivedData 캐시입니다. Product → Clean Build Folder(⇧⌘K)를 통해 DerivedData를 지우거나 ~/Library/Developer/Xcode/DerivedData 폴더를 수동으로 삭제하세요. 정리 후 Canvas는 미리보기를 처음부터 다시 빌드합니다.
문제 2: PreviewProvider가 @StateObject를 인식하지 못함. PreviewProvider는 View의 정적 인스턴스를 생성하므로 주입이 필요한 종속성(ViewModel, 서비스)은 초기화 프로그램이나 기본값이 있는 @StateObject를 통해 전달되어야 합니다. 미리보기에서는 실제 서비스 대신 모의 객체를 사용하세요.
문제 3: Canvas에서 애니메이션이 작동하지 않음. Canvas는 모든 SwiftUI 애니메이션을 지원하지 않습니다 — 특히 타이밍에 의존하는 애니메이션(withAnimation 지연 포함, .spring)이 그렇습니다. 애니메이션 테스트를 위해 시뮬레이터에서 애플리케이션을 실행하세요. Canvas는 정적 레이아웃 확인에 적합합니다.
의존성 주입은 복잡한 ViewModel에서 PreviewProvider를 작동하게 하는 가장 좋은 방법입니다. 테스트 데이터가 있는 별도의 ViewModel 인스턴스를 만들고 View 초기화 프로그램에 전달하세요.
struct DashboardView: View {
@StateObject var viewModel: DashboardViewModel
var body: some View {
List(viewModel.items) { item in
Text(item.title)
}
}
}
struct DashboardView_Previews: PreviewProvider {
static var previews: some View {
DashboardView(viewModel: DashboardViewModel.mock)
}
}
모의 확장: ViewModel에 대한 extension을 만들어 정적 .mock 인스턴스를 제공합니다. 이렇게 하면 테스트 데이터를 ViewModel 가까이에 유지하고 PreviewProvider를 읽기 쉽게 만듭니다.
자주 묻는 질문
기술적으로는 아닙니다 — PreviewProvider 없이도 애플리케이션이 컴파일됩니다. 그러나 실제로 Apple과 SwiftUI 커뮤니티는 모든 공개 View에 미리보기를 작성할 것을 권장합니다. PreviewProvider는 개발을 가속화하고 다양한 기기에서 레이아웃을 빠르게 확인할 수 있게 하며 팀을 위한 시각적 문서 역할을 합니다.
PreviewProvider는 Debug 빌드에서만 코드를 추가하므로 미리보기가 릴리스 구성에서 사용할 수 없는 유형을 사용하는 경우 컴파일 오류가 발생할 수 있습니다. Canvas를 지원하지 않는 플랫폼에서 @available을 사용하거나 미리보기 복잡성 제한을 초과하는 경우에도 오류가 발생합니다.
직접 전달할 수 없습니다. PreviewProvider는 격리되어 실행됩니다. 모의 데이터를 사용하세요: .mock 인스턴스가 있는 정적 모델 extension을 만듭니다. @StateObject가 있는 View의 경우 초기화 프로그램을 통해 테스트 데이터가 있는 ViewModel을 전달합니다. 이렇게 하면 네트워크 요청 없이 실제 데이터를 시뮬레이션합니다.
아니요, PreviewProvider는 릴리스 바이너리 크기에 영향을 미치지 않습니다. Xcode는 조건부 컴파일(#if DEBUG / #if !RELEASE)을 사용하여 릴리스 빌드에서 미리보기 코드를 제외합니다. PreviewProvider 코드는 Debug 구성에서만 존재하며 App Store 빌드에 포함되지 않습니다.
네, Xcode는 미리보기 디버깅을 지원합니다. previews 또는 View 코드 내에 중단점을 설정하고 Product → Preview → Debug Preview를 선택하세요. Canvas 렌더링 중에 중단점이 트리거됩니다. 이는 미리보기에서만 볼 수 있는 레이아웃 문제 분석에 유용합니다.
요약
턴키 방식의 모바일 애플리케이션을 개발해 드립니다
IT Sectr는 2017년부터 스타트업과 기업을 위한 iOS 및 Android 애플리케이션을 만듭니다. 저희가 상담해 드리고 최적의 솔루션을 제안하겠습니다.