用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
直接命令不会经过审查 Prompt;运行前请先检查来源。
npx skills add https://github.com/SAM42-Lab/everything-claude-code-kr --skill swiftui-patterns命令会保持在同一行。复制前请横向滚动并检查完整内容。
想先保存到本地?可下载 SkillsMP 当前能够提供的文件。
캡처, 진단, 억제된 복구 및 인트로스펙션 보고서를 사용하여 AI 에이전트 실패에 대한 구조화된 셀프 디버깅 워크플로우를 수행합니다.
기술, 명령어, 규칙, 훅 및 기타 요소를 DAILY 대 LIBRARY 버킷으로 분류하여 특정 저장소에 대한 증거 기반의 ECC 설치 계획을 수립합니다. 전체 번들을 로드하는 대신 프로젝트에 실제로 필요한 것만 ECC를 트리밍해야 할 때 사용하세요.
리소스 명명, 상태 코드, 페이지네이션, 필터링, 에러 응답, 버전 관리 및 프로덕션 API를 위한 속도 제한을 포함한 REST API 설계 패턴.
基于 SOC 职业分类
正在显示 SKILL.md
| name | swiftui-patterns |
| description | SwiftUI 아키텍처 패턴, @Observable을 사용한 상태 관리, 뷰 구성, 네비게이션, 성능 최적화 및 현대적인 iOS/macOS UI 모범 사례입니다. |
Apple 플랫폼에서 선언적이고 성능이 뛰어난 사용자 인터페이스를 구축하기 위한 현대적인 SwiftUI 패턴입니다. Observation 프레임워크, 뷰 구성, 타입 안전 네비게이션 및 성능 최적화를 다룹니다.
@State, @Observable, @Binding)NavigationStack을 사용하여 네비게이션 흐름을 설계할 때상황에 맞는 가장 단순한 래퍼를 선택하세요:
| 래퍼 | 사용 사례 |
|---|---|
@State | 뷰 로컬 값 타입 (토글, 폼 필드, 시트 표시 여부 등) |
@Binding | 부모 뷰의 @State에 대한 양방향 참조 |
@Observable 클래스 + @State | 여러 프로퍼티를 가진 소유된 모델 |
@Observable 클래스 (래퍼 없음) | 부모로부터 전달받은 읽기 전용 참조 |
@Bindable | @Observable 프로퍼티에 대한 양방향 바인딩 |
@Environment | .environment()를 통해 주입된 공유 의존성 |
ObservableObject 대신 @Observable을 사용하세요. 프로퍼티 수준의 변경을 추적하므로, 변경된 프로퍼티를 읽는 뷰만 다시 렌더링됩니다.
@Observable
final class ItemListViewModel {
private(set) var items: [Item] = []
private(set) var isLoading = false
var searchText = ""
private let repository: any ItemRepository
init(repository: any ItemRepository = DefaultItemRepository()) {
self.repository = repository
}
func load() async {
isLoading = true
defer { isLoading = false }
items = (try? await repository.fetchAll()) ?? []
}
}
struct ItemListView: View {
@State private var viewModel: ItemListViewModel
init(viewModel: ItemListViewModel = ItemListViewModel()) {
_viewModel = State(initialValue: viewModel)
}
var body: some View {
List(viewModel.items) { item in
ItemRow(item = item)
}
.searchable(text: $viewModel.searchText)
.overlay { if viewModel.isLoading { ProgressView() } }
.task { await viewModel.load() }
}
}
@EnvironmentObject를 @Environment로 교체하세요:
// 주입
ContentView()
.environment(authManager)
// 사용
struct ProfileView: View {
@Environment(AuthManager.self) private var auth
var body: some View {
Text(auth.currentUser?.name ?? "Guest")
}
}
뷰를 작고 집중된 구조체로 분리하세요. 상태가 변경될 때 해당 상태를 읽는 하위 뷰만 다시 렌더링됩니다.
struct OrderView: View {
@State private var viewModel = OrderViewModel()
var body: some View {
VStack {
OrderHeader(title: viewModel.title)
OrderItemList(items: viewModel.items)
OrderTotal(total: viewModel.total)
}
}
}
struct CardModifier: ViewModifier {
func body(content: Content) -> some View {
content
.padding()
.background(.regularMaterial)
.clipShape(RoundedRectangle(cornerRadius: 12))
}
}
extension View {
func cardStyle() -> some View {
modifier(CardModifier())
}
}
프로그래밍 방식의 타입 안전 라우팅을 위해 NavigationStack과 NavigationPath를 사용하세요.
@Observable
final class Router {
var path = NavigationPath()
func navigate(to destination: Destination) {
path.append(destination)
}
func popToRoot() {
path = NavigationPath()
}
}
enum Destination: Hashable {
case detail(Item.ID)
case settings
case profile(User.ID)
}
struct RootView: View {
@State private var router = Router()
var body: some View {
NavigationStack(path: $router.path) {
HomeView()
.navigationDestination(for: Destination.self) { dest in
switch dest {
case .detail(let id): ItemDetailView(itemID: id)
case .settings: SettingsView()
case .profile( id): (userID: id)
}
}
}
.environment(router)
}
}
LazyVStack과 LazyHStack은 화면에 보일 때만 뷰를 생성합니다.
ScrollView {
LazyVStack(spacing: 8) {
ForEach(items) { item in
ItemRow(item: item)
}
}
}
ForEach에서는 항상 안정적이고 고유한 ID를 사용하세요. 배열 인덱스 사용을 피하세요.
// Identifiable 준수 또는 명시적 id 사용
ForEach(items, id: \.stableID) { item in
ItemRow(item: item)
}
body 내부에서 I/O, 네트워크 호출 또는 무거운 계산을 수행하지 마세요..task {}를 사용하세요. 뷰가 사라질 때 자동으로 취소됩니다..sensoryFeedback() 및 .geometryGroup() 사용을 절제하세요..shadow(), .blur(), .mask() 사용을 최소화하세요. 오프스크린 렌더링을 유발합니다.body 연산이 매우 무거운 뷰의 경우, Equatable을 준수하여 불필요한 재렌더링을 건너뛰게 하세요.
struct ExpensiveChartView: View, Equatable {
let dataPoints: [DataPoint] // DataPoint는 Equatable을 준수해야 함
static func == (lhs: Self, rhs: Self) -> Bool {
lhs.dataPoints == rhs.dataPoints
}
var body: some View {
// 복잡한 차트 렌더링 로직
}
}
빠른 반복 개발을 위해 인라인 모킹 데이터를 포함한 #Preview 매크로를 사용하세요.
#Preview("비어 있는 상태") {
ItemListView(viewModel: ItemListViewModel(repository: EmptyMockRepository()))
}
#Preview("데이터 있음") {
ItemListView(viewModel: ItemListViewModel(repository: PopulatedMockRepository()))
}
ObservableObject / @Published / @StateObject / @EnvironmentObject 사용 — @Observable로 마이그레이션하세요.body나 init에서 직접 비동기 작업 수행 — .task {}나 명시적인 로드 메서드를 사용하세요.@State로 생성 — 부모로부터 전달받으세요.AnyView 타입 지우기 사용 — 조건부 뷰에는 @ViewBuilder나 Group을 선호하세요.Sendable 요구 사항 무시.액터 기반 영속성 패턴은 swift-actor-persistence 스킬을 참조하세요.
프로토콜 기반 DI 및 Swift Testing을 사용한 테스트는 swift-protocol-di-testing 스킬을 참조하세요.