SwiftUI 멀티 플랫폼 아키텍처 (iOS, iPadOS, macOS, visionOS)
Source: Dev.to
위에 제공된 소스 링크 외에 번역할 텍스트가 포함되어 있지 않습니다. 번역을 원하는 전체 내용을 제공해 주시면 한국어로 번역해 드리겠습니다.
🧠 핵심 원칙
동작을 공유합니다.
프레젠테이션을 특화합니다.
- 비즈니스 로직은 100 % 공유되어야 합니다.
- UI 구성은 플랫폼마다 다르게 적용됩니다.
🧱 1. 기능별로 구분하고, 플랫폼별로 구분하지 않기
나쁜 구조
iOS/
macOS/
Shared/
좋은 구조
Features/
Home/
Profile/
Settings/
Platform/
iOS/
macOS/
visionOS/
각 기능은 다음을 포함합니다:
- ViewModel
- State
- Business logic
플랫폼 폴더는 다음을 포함합니다:
- Wrappers
- Layout adapters
- Platform‑specific views
🧩 2. 플랫폼 추상화 레이어
작은 어댑터를 만들기:
protocol PlatformMetrics {
var sidebarWidth: CGFloat { get }
var toolbarHeight: CGFloat { get }
}
플랫폼별 구현:
struct iOSMetrics: PlatformMetrics {
let sidebarWidth: CGFloat = 0
let toolbarHeight: CGFloat = 44
}
struct macOSMetrics: PlatformMetrics {
let sidebarWidth: CGFloat = 240
let toolbarHeight: CGFloat = 52
}
적절한 구현을 주입하기:
.environment(\.metrics, currentMetrics)
뷰 내부에 조건문이 필요하지 않습니다.
🧭 3. 플랫폼별 내비게이션 아키텍처
| Platform | Navigation style |
|---|---|
| iPhone | 단일 스택, 푸시 기반 |
| iPad | 분할 뷰, 컬럼 내비게이션 |
| macOS | 사이드바 + 디테일, 다중‑윈도우 |
| visionOS | 공간 스택, 씬‑기반 내비게이션 |
단일 내비게이션 모델을 강제하지 마세요. 대신:
struct RootView: View {
var body: some View {
PlatformContainer {
HomeFeature()
}
}
}
PlatformContainer는 현재 플랫폼에 따라 구현을 전환합니다.
🪟 4. 윈도우 및 씬 관리
macOS와 visionOS는 윈도우‑우선 플랫폼입니다. 명시적으로 설계하세요:
WindowGroup {
RootView()
}
WindowGroup(id: "inspector") {
InspectorView()
}
iOS에서는 이러한 그룹이 무시되지만, macOS에서는 필수적입니다. 아키텍처는 여러 인스턴스를 가정해야 합니다.
🧠 5. 입력 모델 차이점
| 플랫폼 | 입력 양식 |
|---|---|
| iOS | 터치, 제스처, 스와이프 |
| macOS | 포인터, 호버, 오른쪽 클릭, 키보드 |
| visionOS | 시선, 핀치, 공간 포커스 |
절대로 단독으로 의존하지 마세요:
.onTapGesture { … }
항상 지원하세요:
Button(키보드 단축키 포함)- 포커스 처리
- 컨텍스트 메뉴
⌨️ 6. 키보드 및 명령 시스템
macOS와 iPad는 명령 정의가 필요합니다:
.commands {
CommandGroup(replacing: .newItem) {
Button("New Item") {
create()
}
.keyboardShortcut("N")
}
}
공유 로직에서 액션을 노출합니다:
func create()
func delete()
func refresh()
UI 레이어가 이러한 액션을 연결하고, 기본 로직은 공유된 상태를 유지합니다.
📐 7. 레이아웃 전략
고정 레이아웃을 피하세요. 적응형 스택, 유연한 그리드, 동적 타입 및 사이즈 클래스를 사용하세요. 예시 패턴:
if horizontalSizeClass == .compact {
CompactLayout()
} else {
RegularLayout()
}
이 로직은 기능 뷰가 아니라 레이아웃 컨테이너에 분리하세요—기능 뷰에 두지 마세요.
🧪 8. 멀티플랫폼 정확성 테스트
다음 항목에 대해 플랫폼 간 테스트:
- 윈도우 생성
- 플랫폼별 딥링크
- 키보드 탐색 및 포커스 동작
- 스플릿‑뷰 상태
- 멀티 윈도우 복원
대부분의 멀티플랫폼 버그는 UI보다 상태와 관련되어 있습니다.
❌ 9. 일반적인 안티‑패턴
피해야 할 것:
#if os(iOS)를 기능 뷰 안에 사용- ViewModel 안에서 플랫폼 검사
- 중복된 비즈니스 로직
- 모든 곳에서 단일 UI를 강제하는 네비게이션 해킹
해결책이 억지로 느껴진다면, 아마도 그렇습니다.
🧠 10. 멘탈 모델
계층적으로 생각하세요:
Business Logic (shared)
State Management (shared)
Navigation Model (per platform)
Layout System (per platform)
Input Model (per platform)
Presentation (per platform)
하단 세 계층만 플랫폼마다 달라집니다.
🚀 Final Thoughts
- 기능은 재사용 가능하게 유지됩니다
- 코드는 깔끔하게 유지됩니다
- 플랫폼은 네이티브처럼 느껴집니다
- 유지보수는 합리적으로 유지됩니다
- visionOS 지원이 간단해집니다