Xcode 26에서 재사용 가능한 Preview 모듈 만들기

이경규·2025년 9월 17일

Xcode 26에서 재사용 가능한 Preview 모듈 만들기

요약: 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
  • Bundle.module은 Swift Package의 리소스에 접근하는 안전한 방법입니다.
  • #if DEBUG로 감싸면 릴리즈 빌드에 해당 코드가 포함되지 않음.

추가로 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) 편의 확장

profile
iOS 앱 개발자

0개의 댓글