요약: Swift 패키지(또는 프로젝트 내 타깃)를 이용해 “Preview 전용” 리소스·더미 데이터·헬퍼를 분리하면 SwiftUI 미리보기가 빨라지고, 재사용성·테스트 편의성이 올라갑니다. 이 글은 실무에서 바로 적용 가능한 패턴, 코드 템플릿, 주의사항을 단계별로 정리합니다.
⸻
왜 Preview 전용 모듈을 만들까?
• 뷰를 빠르게 확인하려면 네트워크·DB 의존성이 제거된 더미 데이터가 필요합니다.
• 여러 화면(또는 여러 프로젝트)에서 동일한 샘플 이미지/모델·헬퍼를 공유하면 유지보수가 쉬워집니다.
• #if DEBUG로 릴리즈 빌드에 영향 주지 않고 프리뷰 전용 코드를 안전하게 유지할 수 있습니다.
• Swift Package로 만들면 다른 앱/라이브러리에서도 동일한 Preview 리소스를 재사용 가능.
⸻
핵심 아이디어 (한 문장)
AppPreviews라는 Swift Package(또는 앱 내부의 Preview 타깃)를 만들어 PreviewData, 샘플 이미지(리소스), Preview 전용 헬퍼를 제공하고, 뷰의 PreviewProvider에서 이를 사용하면 끝.
⸻
단계별 구현 가이드
1) Swift Package 생성 (권장)
Xcode → File > New > Package... 로 새 패키지 생성
• 이름: AppPreviews
• Platforms: iOS (최소버전은 앱 상황에 맞게)
• Targets: AppPreviews (라이브러리)
Package.swift 예제:
import PackageDescription
let package = Package(
name: "AppPreviews",
platforms: [.iOS(.v16)],
products: [
.library(name: "AppPreviews", targets: ["AppPreviews"])
],
targets: [
.target(
name: "AppPreviews",
resources: [
.process("PreviewAssets") // sample images, json 등
]
)
]
)
PreviewAssets 폴더를 패키지 루트에 만들고 샘플 이미지(예: sample1.png) 넣기.
⸻
2) Preview 데이터와 헬퍼 만들기
패키지 내부에 PreviewData.swift 파일 추가:
#if DEBUG
import Foundation
import UIKit
import SwiftUI
public enum PreviewData {
// 모델 더미 예시
public struct Photo {
public let id: String
public let title: String
public let date: Date
public let imageName: String
}
public static var samplePhoto: Photo {
Photo(id: "p1", title: "Sample Photo", date: Date(), imageName: "sample1")
}
// UIImage 로드 (Bundle.module 사용)
public static var sampleUIImage: UIImage {
let bundle = Bundle.module
return UIImage(named: "sample1", in: bundle, with: nil) ?? UIImage()
}
// 샘플 ViewModel (간단 mock)
public static var cameraViewModelMock: CameraViewModel {
CameraViewModel(isPreview: true)
}
}
#endif
추가로 Image 편의 확장:
#if DEBUG
import SwiftUI
public extension Image {
static func preview(_ name: String) -> Image {
Image(name, bundle: .module)
}
}
#endif
⸻
3) 앱에 패키지 연결하기
• 프로젝트 → Package Dependencies → + → 로컬 패키지(또는 Git URL) 추가
• 앱 타깃에서 AppPreviews를 임포트하여 사용
⸻
4) 뷰에서 PreviewData 사용 (예시)
CameraView.swift의 Preview 부분:
import SwiftUI
import AppPreviews
struct CameraView: View {
var vm: CameraViewModel
var body: some View {
VStack {
Text(vm.title)
Image.preview("sample1")
.resizable()
.scaledToFit()
}
}
}
struct CameraView_Previews: PreviewProvider {
static var previews: some View {
Group {
CameraView(vm: PreviewData.cameraViewModelMock)
.previewDevice("iPhone 15 Pro")
CameraView(vm: PreviewData.cameraViewModelMock)
.preferredColorScheme(.dark)
}
}
}
⸻
실무 팁 & 모범 사례
리소스 관리
• 벡터 PDF는 Scales = Single Vector PDF로 넣어두면 다양한 해상도에서 선명.
• 이미지 이름 충돌 방지: Preview 패키지의 이미지 이름은 접두사(preview_)를 붙여 구분.
API 설계
• Preview 패키지는 공개 API만 제공하세요. (public 타입/메서드)
• 앱 내부에서만 쓰일 mock 타입은 #if DEBUG로 감싸 내부 구현을 숨기면 안전.
환경 기반 분기
EnvironmentKey로 preview 모드 신호를 전달하면 런타임 로직을 분기하기 쉬움:
private struct IsPreviewKey: EnvironmentKey {
static let defaultValue: Bool = false
}
extension EnvironmentValues {
var isPreview: Bool {
get { self[IsPreviewKey.self] }
set { self[IsPreviewKey.self] = newValue }
}
}
미리보기에서 environment(.isPreview, true) 설정.
Mock Network
• Preview 패키지에 MockNetwork를 포함시켜 API 레이어를 무력화하고, 미리보기 전용 데이터를 반환하게 하세요.
• 실제 앱에서는 의존성 주입으로 런타임 네트워크와 교체.
Preview 다양성
• 여러 기기, 라이트/다크, Dynamic Type, Accessibility 옵션을 Previews에 넣어 UI를 폭넓게 점검하세요:
.preferredColorScheme(.dark)
.environment(\.sizeCategory, .accessibilityExtraLarge)
성능 팁
• Preview에 heavy 연산(예: 이미지 디코딩, 모델 로딩)을 직접 실행하지 마세요. 미리 생성한 가벼운 샘플을 사용하세요.
• Preview 패키지의 리소스는 작게(수십 KB~수백 KB) 유지.
⸻
자주 겪는 문제 & 해결
• Preview에서 이미지가 보이지 않음
-> Swift Package에 이미지를 넣었다면 Image("name", bundle: .module)로 불러야 함. 앱의 Asset과 이름이 겹쳐도 충돌 가능성이 있으니 확인.
• 패키지 변경 후 Preview가 갱신되지 않음
-> Xcode Clean (Cmd+Shift+K) + Rebuild 또는 Xcode 재시작 권장.
• 릴리즈에 Debug 코드가 포함됨
-> #if DEBUG를 빠뜨리지 않았는지 확인.
⸻
정리 — 왜 이 패턴이 좋은가?
• 빠른 UI iteration: 더미 데이터로 즉시 시각 검증 가능
• 재사용성: 단일 패키지로 여러 프로젝트/타깃에서 공유
• 안전성: #if DEBUG + 공개 API 설계로 릴리즈 영향 최소화
• 협업: 디자이너/PM도 동일 샘플로 UI 확인 가능
⸻
코드 템플릿(요약)
• Package.swift — resources 포함
• PreviewAssets/ — 샘플 이미지들
• PreviewData.swift — mock 모델·ViewModel·이미지 로더
• Image+Preview.swift — Image(name, bundle: .module) 편의 확장
⸻