Communitygithub.com

SwiftUI 전문가

올바른 상태 소유권, 범위가 지정된 무효화, 부드러운 목록 스크롤로 깔끔하고 성능이 뛰어나며 접근성 높은 SwiftUI 뷰를 구축하고, 기존 SwiftUI 코드를 구체적인 프레임 시간 및 재렌더링 예산에 대해 검토합니다.

SwiftUI 전문가란 무엇인가요?

이 스킬은 SwiftUI 앱의 성능과 안정성을 크게 향상시키는 전문 지식을 제공합니다. 주로 Claude Code, Cursor 등 SwiftUI 개발을 지원하는 AI 에이전트와 함께 사용됩니다. 핵심은 '상태 소유권'입니다. 부적절한 위치에 상태를 두면 키 입력 한 번에 전체 화면 트리가 재평가되고, 목록이 버벅거리며, 애니메이션이 끊어집니다. 이 스킬은 상태 변경의 영향을 받는 뷰로만 무효화 범위를 제한하여 프레임 예산(120Hz 기준 8.3ms, 60Hz 기준 16.7ms)을 준수하고, 접근성(Dynamic Type, VoiceOver)을 기본으로 지원합니다. 구체적인 운영 절차(Step 1~6)를 통해 데이터 수집, 상태 소유권 결정, 뷰 분할, 리스트 최적화, 애니메이션, 접근성 작업을 순차적으로 수행합니다. 또한 잘못된 코드 예제와 개선된 코드 예제를 제공하여 구체적인 학습을 돕습니다. 단, React Native, Flutter, Android Compose UI에는 사용하지 말고 각각 전용 스킬을 사용해야 합니다.

지원 대상~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/SkillMedev/skills/tree/HEAD/skills/swift-ui

즐겨 사용하는 AI에게 물어보기

이 에이전트 스킬이 미리 로드된 새 채팅을 엽니다.

문서

SwiftUI 전문가은(는) 무엇을 하나요?

SwiftUI 화면은 상태 소유권에 의해 성패가 결정됩니다. 상태를 잘못된 위치에 두면 모든 키 입력마다 전체 트리가 재평가되고, 목록이 버벅거리며, 애니메이션이 끊어집니다. 이 스킬은 SwiftUI 뷰를 구축하고 검토하여 무효화가 실제로 변경된 데이터를 읽는 뷰로만 범위가 제한되고, 스크롤 중 프레임 예산을 유지하며, 결과물이 사후에 추가되는 것이 아니라 기본적으로 접근성을 갖추도록 합니다.

운영 절차

상태 설계가 이후 모든 것을 결정하기 때문에 이 순서대로 작업하십시오. 뷰 계층 구조를 구축한 후 상태를 수정하려면 계층 구조를 다시 작성해야 합니다.

1단계: 입력 수집

뷰 코드를 작성하기 전에 수집합니다. 사용자가 모르는 경우 기본값을 사용하고 추측이라고 표시합니다.

  • 대상 기기 및 재생률 (기본값: ProMotion 120Hz iPhone 및 60Hz 기준 기기 가정).
  • 데이터 형태: 가장 큰 목록의 항목 수, 데이터 변경 빈도, 스트리밍 여부.
  • 소유권 맵: 각 상태 조각에 대해 어떤 뷰가 생성하고, 어떤 뷰가 읽고, 어떤 뷰가 변경하는지.
  • 기본 이상의 접근성 요구사항 (기본값: 전체 Dynamic Type + VoiceOver 지원).

2단계: 값별 상태 소유권 선택

작동하는 가장 좁은 래퍼를 선택합니다.

  • @State - 로컬, 뷰 소유, 값 유형 상태. 또한 뷰가 생성한 @Observable 모델 인스턴스의 올바른 소유자입니다.
  • @Binding - 다른 곳에서 소유한 상태에 대한 양방향 참조. 자식이 변경할 때만 바인딩을 전달하고, 읽기만 할 때는 일반 값을 전달합니다.
  • @Observable (Observation 프레임워크) - 모델 객체; 뷰는 읽은 속성만 관찰하므로 무효화는 객체별이 아닌 속성별로 발생합니다.
  • @Environment - 서비스 및 공유 모델에 대한 의존성 주입을 트리 아래로 전달합니다.

규칙: 상태는 해당 상태를 읽거나 쓰는 모든 뷰의 가장 가까운 공통 조상에 위치해야 합니다. 그보다 낮으면 (뷰가 사라질 때 재설정됨) 안 되고, 더 높으면 (무효화 범위가 넓어짐) 안 됩니다.

3단계: 무효화 범위를 좁히기 위해 뷰 구성

  • body를 작게 유지하고, 서브뷰를 추출하여 변경이 화면 전체가 아닌 하나의 행에만 영향을 미치도록 합니다. 약 50줄 또는 세 단계 중첩을 초과하는 body는 분할 대상입니다.
  • 서브뷰에 최소한의 데이터만 전달합니다 - 전체 저장소가 아닌 item.title을 전달하여 영향받는 뷰만 다시 렌더링되도록 합니다.
  • 거대한 중첩 클로저 대신 @ViewBuilder 헬퍼를 사용합니다.
  • body에서 무거운 작업(형식 지정, 정렬, 필터링, 디코딩)을 절대 수행하지 마십시오. 모델에서 계산하고 완성된 값을 뷰에 전달하십시오. body는 마이크로초 범위를 유지해야 하며, 애니메이션 중에는 매 프레임 실행될 수 있습니다.

4단계: 목록 및 프레임 예산

예산은 120Hz에서 프레임당 8.3ms, 60Hz에서 16.7ms입니다. 이는 해당 프레임의 메인 스레드에 있는 모든 작업(행만이 아님)을 포함합니다. 실용적인 규칙:

  • 약 50행 이상인 경우 List 또는 LazyVStack을 사용하여 행이 필요할 때 렌더링되도록 합니다. ScrollView 안의 일반 VStack은 모든 행을 미리 생성합니다.
  • 데이터의 안정적인 id (item.id)를 항목에 제공하고, 배열 인덱스나 body에서 계산된 UUID()를 절대 사용하지 마십시오. 불안정한 id는 행 식별성을 파괴하여 깜박임, 스크롤 위치 손실, 행 상태 손실을 유발합니다.
  • 행은 일정한 비용이 들어야 합니다: 행별 날짜 포맷터나 이미지 디코딩이 없어야 합니다. 포맷터를 캐시하고, AsyncImage 또는 캐싱 이미지 파이프라인을 사용하십시오.
  • Instruments의 SwiftUI 템플릿으로 확인: 스크롤하는 동안 뷰 본문 평가 횟수를 관찰하십시오. 관련 없는 상태가 변경될 때 본문이 평가되는 행 유형은 상태 소유권 버그입니다 - 2단계를 수정하고 주변에 메모이제이션하지 마십시오.

5단계: 상태로부터 애니메이션

  • 상태로부터 애니메이션을 구동합니다: withAnimation { model.expanded.toggle() }.
  • 암시적 전역 애니메이션(의도하지 않은 것들을 애니메이션함)보다 특정 값에 범위가 지정된 .animation(_:value:)를 선호합니다.
  • 공유 요소 전환에는 matchedGeometryEffect를, 삽입/제거에는 transition을 사용합니다.
  • accessibilityReduceMotion을 존중합니다: 설정된 경우 이동을 불투명도 페이드로 대체합니다.

6단계: 접근성 검토

  • accessibilityLabel/accessibilityValue를 추가하고, 관련 요소를 accessibilityElement(children: .combine)으로 그룹화하여 행이 다섯 개의 조각이 아닌 하나의 문장으로 읽히도록 합니다.
  • Dynamic Type을 존중합니다 - 시스템 텍스트 스타일을 사용하고, 텍스트를 자르는 고정 프레임을 피하며, 가장 큰 접근성 크기에서 확인합니다.
  • 대비를 확인하고 다크 모드, 큰 Dynamic Type, 빈/로딩/오류 상태에 대한 #Preview 변형을 샘플 데이터와 함께 추가합니다.

작업 예시: 상태 소유권, 나쁨 vs 좋음

나쁨 - 검색 텍스트가 전체 트리가 관찰하는 모델에 있고, 행이 전체 저장소를 수신하기 때문에 모든 키 입력에 전체 화면이 무효화됩니다:

@Observable final class ScreenStore {
  var searchText = ""
  var items: [Item] = []
}

struct ContactList: View {
  @State private var store = ScreenStore()
  var body: some View {
    VStack {
      TextField("Search", text: $store.searchText)
      ForEach(store.items) { item in
        ContactRow(store: store, item: item) // 행이 모든 것을 관찰
      }
    }
  }
}

좋음 - 검색 텍스트는 뷰 로컬이고, 행은 읽는 값만 받으며, 목록은 지연 로딩되고 안정적인 id를 사용합니다:

struct ContactList: View {
  @State private var searchText = ""
  @Environment(ContactModel.self) private var model
  var body: some View {
    List(model.filtered(searchText)) { item in
      ContactRow(name: item.name, isOnline: item.isOnline)
    }
    .searchable(text: $searchText)
  }
}

struct ContactRow: View {
  let name: String
  let isOnline: Bool
  var body: some View {
    Label(name, systemImage: isOnline ? "circle.fill" : "circle")
  }
}

좋은 버전에서 입력하면 List 내용 클로저와 필터된 멤버십이 변경된 행만 무효화됩니다 - 그 외에는 아무것도 무효화되지 않습니다.

인도물

작동하는 SwiftUI 뷰 코드와 함께 각 상태 조각에 대해 소유자, 래퍼, 읽기/쓰기를 수행하는 뷰를 명시한 한 문단 분량의 상태 맵을 생성합니다. 검토의 경우 프레임 예산 영향 순서대로 정렬된 결과 목록을 각각의 수정 사항과 함께 생성합니다.

하지 말아야 할 것

  • body 평가 중에는 절대 상태를 변경하지 마십시오 - 루프가 발생하거나 정의되지 않은 동작 경고가 트리거됩니다.
  • onAppear에서 원시 Task로 비동기 작업을 수행하지 마십시오 - 대신 .task {}를 사용하면 사라질 때 자동으로 취소됩니다.
  • 모델에 뷰 유형(Color, Image, AnyView)을 넣지 마십시오. 모델은 UI 없이도 테스트 가능해야 합니다.
  • "단순함을 위해" 모든 상태를 하나의 화면 수준 저장소로 끌어올리지 마십시오 - 이것이 정확히 모든 키 입력마다 화면을 다시 그리게 만드는 패턴입니다.
  • 소유권을 수정하기 전에 equatable() 또는 캐싱으로 무효화 버그를 덮지 마십시오. 버그는 동일한 객체를 관찰하는 다음 뷰에서 다시 나타날 것입니다.
  • 텍스트에 고정 프레임을 사용하지 마십시오 - Dynamic Type이 텍스트를 자를 것입니다.

품질 기준

완성된 뷰는 다음 기준을 통과해야 합니다.

  • 모든 상태 조각에는 정확히 하나의 소유자와 작동하는 가장 좁은 래퍼가 있습니다.
  • Instruments는 행 본문이 자체 데이터가 변경될 때만 평가됨을 보여줍니다.
  • 예상되는 가장 큰 목록을 스크롤해도 기준 60Hz 기기에서 프레임 예산을 유지합니다.
  • 수명이 긴 상태는 사라질 수 있는 뷰 위로 끌어올려져 탐색 중에도 유지됩니다.
  • 키보드 회피 및 안전 영역이 처리됩니다 (safeAreaInset, scrollDismissesKeyboard).
  • VoiceOver는 각 상호 작용 요소를 의미 있는 레이블로 읽습니다. 레이아웃은 가장 큰 Dynamic Type 크기에서도 유지됩니다. reduceMotion이 존중됩니다.
  • 로딩, 빈 상태, 오류, 다크 모드, 큰 글꼴 상태에 대한 프리뷰가 존재합니다.

단일 화면을 넘어 앱 전체 프로파일링이 필요한 경우 mobile-perf-profiler와 함께 사용하십시오.

Individual skills in this repo

This repo contains 19 individual skills — each has its own dedicated page.

SkillMedev/skills

Designs REST API surfaces - resource naming, HTTP method and status-code semantics, error shapes, pagination, and filtering - and delivers an endpoint spec a consumer can build against without asking questions. Use when someone asks "how should I name this endpoint", "what status code should this return", "should this be PUT or PATCH", "how do I paginate this list", or is reviewing an API before it ships to external consumers. Do NOT use for planning breaking-change rollouts and deprecation windows - use api-versioning-strategist instead; for GraphQL type and resolver design - use graphql-schema instead; for generating client SDKs from an existing spec - use api-client-generator instead; for designing inbound webhook endpoints - use webhook-receiver-hardener instead.

SkillMedev/skills

Produce an accurate, properly timed caption track (SRT or WebVTT) from a video's audio - transcribing or aligning to the voiceover script, timing cues to speech, and enforcing line-length and reading-speed rules so captions are readable and in sync. Use when someone says "generate captions", "make subtitles from the audio", "transcribe and caption this", "export an SRT or VTT", "the captions are out of sync", or "the subtitles flash by too fast to read". Do NOT use to burn-in, style, reframe, or position an existing caption track for a platform (9:16, brand styling, safe areas) - that is social-video-formatter; do NOT use to animate text word-by-word as a motion graphic - that is kinetic-typography; do NOT use to write the spoken script in the first place - that is narration-script.

SkillMedev/skills

Turns data and charts into a decision-driving narrative structured as headline finding, trend, implication, and recommended action - with finding-led chart titles, context for every number, annotation guidance, and honest flags on any conclusion the data cannot support. Use when someone says "turn these numbers into a story", "what's the takeaway from this data", "help me present these results to leadership", or has charts but no narrative. Do NOT use for compressing a long document into a one-pager - use executive-summary instead - or for running the analysis that produces the findings - use eda-playbook instead.

SkillMedev/skills

Use when a task needs live or historical money data - "convert USD to EUR", "current/past exchange rate", "FX rate on this date / over this range", or "current price of Bitcoin/Ethereum, market cap, 24h change". Frankfurter (ECB reference rates, no key) is the FX default; CoinGecko's free keyless tier covers crypto. Do NOT use for stock quotes or equities - no keyless stock API survives verification, say so instead of guessing; do NOT use for country economic indicators like GDP or inflation series - use government-open-data instead; if the request is a vague "I need live data", route through public-data-api-picker.

SkillMedev/skills

Builds a driver-based FP&A operating model linking business inputs to P&L, balance sheet, and cash flow outputs. Use when building an annual plan, preparing investor materials, running scenario analysis, or stress-testing the business.

SkillMedev/skills

Use when a task needs live geographic lookups - "geocode this address", "what's at these coordinates" (reverse geocoding), "lat/lon for this city", "which country/state is this ZIP or postal code in", or "country facts: capital, currency, population, flag". Nominatim (OpenStreetMap) is the geocoding default; Zippopotam for postal codes; APICountries for country facts. All keyless. Do NOT use for weather at a location - use weather-climate instead; do NOT use for country-level statistics over time (GDP, population trends) - use government-open-data instead; if the request is a vague "I need live data", route through public-data-api-picker.

SkillMedev/skills

Runs the full Getting Things Done loop - capture, clarify, organize, reflect, engage - building a trusted system of context lists, a projects list with defined next actions, and a weekly review habit. Use when someone says "I'm overwhelmed and things are slipping through the cracks", "set up GTD for me", "help me do a brain dump and organize it", or "my to-do list is a mess". Do NOT use for just running the weekly review ritual itself - use weekly-review instead - or for clearing an email backlog - use inbox-zero.

SkillMedev/skills

Processes any email backlog to zero using the 4Ds - Delete, Delegate, Defer, Do - with a mass-archive strategy for the obvious, a touch-each-email-once discipline, and a keep-it-clear system of batched processing windows, ruthless unsubscribing, filters, and a minimal folder setup. Use when someone says "I have 5,000 unread emails", "help me get to inbox zero", "email is eating my whole day", or treats their inbox as a to-do list. Do NOT use for drafting the reply emails themselves or prioritization rules for an ongoing support queue - use email-triage instead - or for protecting focus time around the email windows - use deep-work-planner instead.

SkillMedev/skills

Write landing-page copy section by section - hero, social proof, features-as-benefits, objections, CTA - leading with one promise and proving it down the page. Use when someone asks "write my landing page", "improve my hero headline", "what should the homepage say", "turn these features into benefits", or is shipping a new page for a launch or campaign. Do NOT use for testing and optimizing an existing page's conversion rate - use landing-page-cro instead; for the one-line claim itself use positioning-statement; for the full message ladder use messaging-hierarchy.

SkillMedev/skills

Improves an existing landing page's conversion rate through evidence-first CRO - audit heatmaps and recordings, write structured hypotheses, prioritize with ICE scoring, and run one-variable tests to statistical significance. Use when someone asks "why isn't my landing page converting", "audit this page before we scale spend", "which A/B test should we run first", or after a CVR drop or ahead of a paid-traffic push. Do NOT use for writing a new landing page from scratch - use landing-page-copy instead. Do NOT use for auditing the ad accounts sending the traffic - use paid-acquisition-audit instead. Do NOT use for reading the results of a finished experiment - use ab-test-analyzer instead.

SkillMedev/skills

Runs structured coaching sessions using values clarification and the GROW model, ending every session with one committed action, a deadline, and an if-then plan for the likely obstacle. Use when someone says "I feel stuck in my life", "help me figure out what I want", "hold me accountable to my goals", or "coach me through this decision". Do NOT use for building a stress toolkit - use stress-management instead - or a journaling practice - use journal-framework; for a standing goal-tracking system, use goals-accountability. Coaching, not therapy: signs of clinical distress route to a licensed professional.

SkillMedev/skills

Adapts English content for a target language and region - swapping idioms, setting the right formality register, replacing cultural references, converting dates, units, and currency - and delivers the localized text with a notes column explaining each adaptation and flagging what needs a native reviewer. Use when someone asks "localize this copy for the Japanese market", "adapt our marketing copy for the Mexican market", "make this translation sound native instead of literal", or a literal translation reads foreign, stiff, or risky. Do NOT use for auditing in-product UI text quality - use ux-writing-audit instead.

SkillMedev/skills

Turns a natural-language video brief into a complete, ready-to-preview Remotion composition - extracts duration, scenes, brand colors, aspect ratio, and real copy; plans the frame budget; and writes data-driven React/TypeScript using useCurrentFrame, interpolate, spring, AbsoluteFill, and Sequence, registered in Root.tsx. Use when someone says "build a 20-second product demo video", "animate a feature walkthrough", "write the Remotion code for this marketing clip", or wants a scene-by-scene composition they can scrub in Studio. Do NOT use for rendering, iterating, or batching the finished MP4 - use remotion-render instead - or for installing and scaffolding the project - use remotion-setup instead.

SkillMedev/skills

Scaffolds a new Remotion video project wired for Claude Code Agent Skills - Node check, create-video scaffold, skills install, folder conventions, Google Fonts, and a smoke-test render. Use whenever someone wants to start making videos with Remotion and Claude, even just "make product videos with Claude.

SkillMedev/skills

Classifies incident severity (SEV1-4) using impact, scope, and urgency signals and decides who to page. Use when an alert fires or a report comes in and a severity call must be made quickly.

SkillMedev/skills

Use the Skill Me catalog from inside any conversation - discover, install, and manage Claude skills through the Skill Me MCP, and load installed skills automatically each session.

SkillMedev/skills

Write one platform-native caption from a topic and brand voice, with a front-loaded hook, native length, and a single earned CTA. Use when the user gives a topic (and optionally brand voice or a described image/video) and asks for an Instagram, LinkedIn, X/Twitter, or TikTok caption. Do NOT use when the user wants a dedicated standalone LinkedIn post - use linkedin-post-writer instead; or a multi-post X thread - use tweet-thread-builder instead; or to adapt one existing piece of content into versions for several channels - use cross-platform-reformatter instead.

SkillMedev/skills

Reframe and export a finished video for social platforms - 9:16 ↔ 16:9 cropping, burned-in captions, a platform-native first frame, loop design, and per-platform specs (aspect, length, safe areas) for TikTok, Reels, Shorts, X, and LinkedIn. Use when someone says "make this vertical", "crop to 9:16", "format for TikTok/Reels/Shorts", "add captions/subtitles", "why is my video cut off on mobile", "resize for Instagram", or "export for social". Do NOT use when the question is about the storyboard or shot order before any video exists (use video-storyboard); the animation craft of how elements move (use motion-design-principles); animated word-by-word caption styling (use kinetic-typography); palette, contrast, or lighting (use motion-color-and-light); directing the product-demo content and screen choreography (use product-demo-director); or scoring, beat-syncing, or audio (use sound-and-music-sync) - this is the craft layer that decides WHAT to format for the feed, then hands a concrete spec to remotion-compo...

SkillMedev/skills

Writes and tunes PySpark jobs - join strategy and broadcast size limits, shuffle-partition sizing, skew diagnosis and salting, UDF avoidance, caching, and output file layout - with concrete size and skew thresholds. Use when someone asks "why is my Spark job slow", "should I broadcast this join", "one task takes forever while the rest finish", "my job OOMs during a join", or is writing a new PySpark ETL job. Do NOT use for Kafka topic, consumer-group, or streaming-pipeline design - use kafka-pipelines instead; do NOT use for single-machine dataframe work that fits in memory - use pandas-expert instead.

관련 스킬