Communitygithub.com

JordanCoin/ios-skills-collection

Apple의 TipKit 프레임워크를 사용하여 인앱 팁, 온보딩 및 기능 발견 UI를 구현, 검토 또는 개선합니다. 기능 발견 툴팁, 온보딩 플로우, 컨텍스트 팁, 첫 실행 경험, 코치 마크를 추가하거나 Tip 프로토콜, TipView, popoverTip, 팁 규칙, 팁 이벤트, 기능 교육 UI 작업 시 사용하세요.

ios-skills-collection란 무엇인가요?

이 스킬은 iOS 17+ 앱에서 Apple의 TipKit 프레임워크를 사용하여 기능 발견 팁, 컨텍스트 힌트 및 온보딩 코치 마크를 구현하는 방법을 안내합니다. TipKit은 표시 빈도, 자격 규칙 및 지속성을 관리하여 팁이 적시에 나타나고 사용자가 기능을 학습하면 사라지도록 합니다. 주요 내용으로는 Tips.configure()를 통한 초기화, Tip 프로토콜 준수를 통한 팁 정의, TipView 및 popoverTip 수정자를 통한 표시, @Parameter 및 Tips.Event를 활용한 규칙 기반 트리거, TipGroup을 통한 팁 순서 제어, 그리고 액션 처리 및 테스트 유틸리티를 포함한 프로그래매틱 제어 방법을 다룹니다. 또한 여러 개의 팁을 동시에 표시하거나 중요한 정보를 팁에 포함시키는 등 일반적인 실수를 피하는 방법과 검토 체크리스트를 제공합니다.

지원 대상~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/JordanCoin/ios-skills-collection/tree/HEAD/skills/dpearson2699--tipkit

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

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

문서

TipKit

iOS 17+ 앱에 Apple의 TipKit 프레임워크를 사용하여 기능 발견 팁, 컨텍스트 힌트 및 온보딩 코치 마크를 추가하세요. TipKit은 표시 빈도, 자격 규칙 및 지속성을 관리하여 팁이 적시에 나타나고 사용자가 기능을 학습하면 사라지도록 합니다.

목차

설정

뷰가 렌더링되기 전에 App.init에서 Tips.configure()를 한 번 호출하세요. 이렇게 하면 팁 데이터 저장소가 초기화되고 규칙 평가가 시작됩니다. 나중에 호출하면 팁 뷰가 데이터 저장소가 준비되기 전에 표시되려고 하는 경합 상태가 발생할 수 있습니다.

import SwiftUI
import TipKit

@main
struct MyApp: App {
    init() {
        try? Tips.configure([
            .datastoreLocation(.applicationDefault)
        ])
    }

    var body: some Scene {
        WindowGroup { ContentView() }
    }
}

DatastoreLocation 옵션

옵션사용 사례
.applicationDefault기본 위치, 앱 샌드박스 (대부분의 앱)
.groupContainer(identifier:)앱과 확장 프로그램 간 팁 상태 공유
.url(_:)저장 위치를 완전히 제어할 수 있는 사용자 정의 파일 URL

CloudKit 동기화

사용자의 여러 기기 간에 팁 상태를 동기화하여 모든 기기에서 동일한 팁이 표시되지 않도록 합니다. 데이터 저장소 위치와 함께 CloudKit 컨테이너 옵션을 추가하세요.

try? Tips.configure([
    .datastoreLocation(.applicationDefault),
    .cloudKitContainer(.named("iCloud.com.example.app"))
])

팁 정의하기

Tip 프로토콜을 준수하는 구조체를 만드세요. 최소한 title을 제공해야 합니다. 지원 세부 정보를 위해 message를, 선행 아이콘을 위해 image를 추가하세요. 팁이 간결한 콜아웃으로 나타나므로 제목을 짧고 행동 지향적으로 유지하세요.

import TipKit

struct FavoriteTip: Tip {
    var title: Text { Text("즐겨찾기 고정") }
    var message: Text? { Text("하트 아이콘을 탭하여 빠르게 접근할 수 있도록 항목을 저장하세요.") }
    var image: Image? { Image(systemName: "heart") }
}

속성: title (필수), message (선택적 세부 정보), image (선택적 선행 아이콘), actions (선택적 버튼), rules (선택적 자격 조건), options (표시 빈도, 최대 횟수).

수명 주기: 보류 중 (규칙 미충족) -> 자격 획득 (모든 규칙 통과) -> 무효화 (해제, 액션 실행 또는 프로그래매틱 방식으로 제거). 무효화되면 데이터 저장소가 재설정되지 않는 한 팁이 다시 나타나지 않습니다.

팁 표시하기

인라인 팁 (TipView 사용)

레이아웃에 TipView를 직접 포함시키세요. 애니메이션과 함께 둥근 카드 형태로 나타나고 사라집니다. 스크롤 가능한 콘텐츠 내의 팁에 사용하세요.

let favoriteTip = FavoriteTip()
var body: some View {
    VStack {
        TipView(favoriteTip)
        ItemListView()
    }
}

Popover 팁 (.popoverTip() 사용)

팁을 특정 뷰에 고정된 팝오버로 연결하세요. 프레임워크가 팝오버에서 앵커까지 화살표를 그립니다. 특정 컨트롤을 가리키는 팁에 사용하세요.

Button { toggleFavorite() } label: { Image(systemName: "heart") }
    .popoverTip(favoriteTip)

// 화살표 방향 제어 (생략 시 시스템이 선택)
.popoverTip(favoriteTip, arrowEdge: .bottom)

사용자 정의 TipViewStyle

앱 전체에서 팁 모양을 제어하는 사용자 정의 스타일을 만드세요. TipViewStyle을 준수하고 makeBody(configuration:)을 구현하세요.

struct CustomTipStyle: TipViewStyle {
    func makeBody(configuration: Configuration) -> some View {
        HStack(spacing: 12) {
            configuration.image?
                .font(.title2)
                .foregroundStyle(.tint)

            VStack(alignment: .leading, spacing: 4) {
                configuration.title
                    .font(.headline)
                configuration.message?
                    .font(.subheadline)
                    .foregroundStyle(.secondary)
            }
        }
        .padding()
    }
}

// 전역 또는 뷰별로 적용
TipView(favoriteTip)
    .tipViewStyle(CustomTipStyle())

팁 규칙

규칙은 팁이 자격을 획득하는 시점을 제어합니다. rules 배열의 모든 규칙이 통과되어야 팁이 표시됩니다. TipKit은 매개변수 기반 규칙과 이벤트 기반 규칙, 두 가지 유형을 지원합니다.

매개변수 기반 규칙

@Parameter를 사용하여 앱 상태를 추적하세요. 매개변수 값이 규칙 조건을 충족하면 팁이 자격을 획득합니다.

struct FavoriteTip: Tip {
    @Parameter
    static var hasSeenList: Bool = false

    var title: Text { Text("즐겨찾기 고정") }

    var rules: [Rule] {
        #Rule(Self.$hasSeenList) { $0 == true }
    }
}

// 사용자가 목록에 도달하면 매개변수 설정
FavoriteTip.hasSeenList = true

이벤트 기반 규칙

Tips.Event를 사용하여 사용자 액션을 추적하세요. 액션이 발생할 때마다 이벤트에 기부(donate)하세요. 기부 횟수 또는 타이밍 조건이 충족되면 규칙이 실행됩니다. 이는 사용자가 관련 기능을 발견하지 않고 액션을 여러 번 수행한 후에 팁을 표시해야 하는 경우에 이상적입니다.

struct ShortcutTip: Tip {
    static let appOpenedEvent = Tips.Event(id: "appOpened")

    var title: Text { Text("빠른 액션 시도") }

    var rules: [Rule] {
        #Rule(Self.appOpenedEvent) { $0.donations.count >= 3 }
    }
}

// 앱이 열릴 때마다 기부
ShortcutTip.appOpenedEvent.donate()

여러 규칙 결합

배열에 여러 규칙을 배치하세요. 모든 규칙이 통과되어야 합니다 (논리적 AND).

struct AdvancedTip: Tip {
    @Parameter
    static var isLoggedIn: Bool = false

    static let featureUsedEvent = Tips.Event(id: "featureUsed")

    var title: Text { Text("고급 모드 잠금 해제") }

    var rules: [Rule] {
        #Rule(Self.$isLoggedIn) { $0 == true }
        #Rule(Self.featureUsedEvent) { $0.donations.count >= 5 }
    }
}

표시 빈도 옵션

options 속성을 사용하여 팁이 표시되는 빈도를 제어하세요.

struct DailyTip: Tip {
    var title: Text { Text("일일 알림") }

    var options: [TipOption] {
        MaxDisplayCount(3)                   // 최대 3회만 표시
        IgnoresDisplayFrequency(true)        // 전역 빈도 제한 무시
    }
}

전역 표시 빈도는 구성 시점에 설정됩니다:

try? Tips.configure([
    .displayFrequency(.daily)  // .immediate, .hourly, .daily, .weekly, .monthly
])

.daily의 경우, 특정 팁이 IgnoresDisplayFrequency(true)를 설정하지 않는 한 시스템은 앱 전체에서 하루에 최대 하나의 팁만 표시합니다.

팁 액션

팁에 액션 버튼을 추가하여 직접 상호 작용을 가능하게 하세요. 각 액션에는 id와 레이블이 있습니다. 팁 뷰의 액션 핸들러에서 액션을 처리하세요.

struct FeatureTip: Tip {
    var title: Text { Text("새 편집기 사용해보기") }
    var message: Text? { Text("강력한 새 편집 모드를 추가했습니다.") }

    var actions: [Action] {
        Action(id: "open-editor", title: "편집기 열기")
        Action(id: "learn-more", title: "더 알아보기")
    }
}

뷰에서 액션 처리:

TipView(featureTip) { action in
    switch action.id {
    case "open-editor":
        navigateToEditor()
        featureTip.invalidate(reason: .actionPerformed)
    case "learn-more":
        showHelpSheet = true
    default:
        break
    }
}

팁 그룹

TipGroup을 사용하여 단일 뷰 내에서 여러 팁을 조정하세요. TipGroup은 그룹에서 한 번에 하나의 팁만 표시되도록 하여 팁 과부하를 방지합니다. 팁은 우선 순위 순서로 표시됩니다.

struct OnboardingView: View {
    let tipGroup = TipGroup(.ordered) {
        WelcomeTip()
        NavigationTip()
        ProfileTip()
    }

    var body: some View {
        VStack {
            if let currentTip = tipGroup.currentTip {
                TipView(currentTip)
            }

            Button("다음") {
                tipGroup.currentTip?.invalidate(reason: .actionPerformed)
            }
        }
    }
}

우선 순위 옵션

초기화 구문동작
.ordered팁이 나열된 순서대로 표시됨

현재 팁이 무효화되면 그룹에서 다음 자격을 갖춘 팁이 currentTip이 됩니다.

프로그래매틱 제어

팁 무효화

사용자가 발견한 액션을 수행하거나 팁이 더 이상 관련이 없을 때 invalidate(reason:)을 호출하세요.

let tip = FavoriteTip()
tip.invalidate(reason: .actionPerformed)
이유사용 시기
.actionPerformed사용자가 팁이 설명하는 액션을 수행함
.displayCountExceeded팁이 최대 표시 횟수에 도달함
.tipClosed사용자가 명시적으로 팁을 해제함

테스트 유틸리티

TipKit은 개발 및 테스트 중에 팁 가시성을 제어하는 정적 메서드를 제공합니다. #if DEBUG 또는 ProcessInfo 검사 뒤에 게이트(gate)하여 프로덕션 빌드에서 실행되지 않도록 하세요.

#if DEBUG
// 규칙에 관계없이 모든 팁 표시 (개발 중에 유용)
Tips.showAllTipsForTesting()

// 특정 팁만 표시
Tips.showTipsForTesting([FavoriteTip.self, ShortcutTip.self])

// 모든 팁 숨기기 (팁을 포함하지 않는 UI 테스트에 유용)
Tips.hideAllTipsForTesting()

// 데이터 저장소 재설정 (모든 팁 상태, 무효화 및 이벤트 지우기)
try? Tips.resetDatastore()
#endif

테스트 스킴을 위한 ProcessInfo 사용

if ProcessInfo.processInfo.arguments.contains("--show-all-tips") {
    Tips.showAllTipsForTesting()
}

개발 빌드의 Xcode 스킴에서 --show-all-tips를 시작 인수로 전달하세요.

일반적인 실수

DON'T: App.init 외부에서 Tips.configure() 호출

뷰의 onAppear 또는 task 수정자에서 Tips.configure()를 호출하면 팁 뷰가 데이터 저장소가 준비되기 전에 렌더링되려고 하는 경합 상태가 발생하여 팁이 누락되거나 깜빡일 수 있습니다.

// 틀림
struct ContentView: View {
    var body: some View {
        Text("Hello")
            .task { try? Tips.configure() }  // 너무 늦음, 뷰가 이미 렌더링됨
    }
}

// 올바름
@main struct MyApp: App {
    init() { try? Tips.configure() }
    var body: some Scene { WindowGroup { ContentView() } }
}

DON'T: 한 번에 너무 많은 팁 표시

여러 팁을 동시에 표시하면 사용자를 압도하고 각 팁의 효과가 희석됩니다. 사용자는 팁을 무시하는 법을 배웁니다.

// 틀림: 동시에 세 개의 팁이 표시됨
VStack {
    TipView(tipA)
    TipView(tipB)
    TipView(tipC)
}

// 올바름: TipGroup을 사용하여 순서 지정
let group = TipGroup(.ordered) { TipA(); TipB(); TipC() }
if let currentTip = group.currentTip {
    TipView(currentTip)
}

DON'T: 사용자가 액션을 수행한 후 팁을 무효화하는 것을 잊음

팁에 "별표를 탭하여 즐겨찾기"라고 표시되어 있고 사용자가 별표를 탭했지만 팁이 계속 표시되면 UI에 대한 신뢰가 떨어집니다.

// 틀림: 사용자가 액션을 수행한 후에도 팁이 계속 표시됨
Button("Favorite") { toggleFavorite() }
    .popoverTip(favoriteTip)

// 올바름: 액션 시 무효화
Button("Favorite") {
    toggleFavorite()
    favoriteTip.invalidate(reason: .actionPerformed)
}
.popoverTip(favoriteTip)

DON'T: 프로덕션에 테스트 팁을 활성화한 상태로 둠

Tips.showAllTipsForTesting()은 모든 규칙과 빈도 제한을 우회합니다. 이 상태로 프로덕션에 배포하면 모든 사용자가 모든 팁을 즉시 보게 됩니다.

// 틀림: 항상 활성화
Tips.showAllTipsForTesting()

// 올바름: DEBUG 뒤에 게이트
#if DEBUG
Tips.showAllTipsForTesting()
#endif

DON'T: 팁 제목을 너무 길게 만듦

긴 제목은 간결한 팁 콜아웃에서 잘리거나 어색하게 줄 바꿈됩니다. 핵심 액션은 제목에, 지원 컨텍스트는 메시지에 넣으세요.

// 틀림
var title: Text { Text("하트 버튼을 탭하여 이 항목을 즐겨찾기 목록에 저장할 수 있습니다") }

// 올바름
var title: Text { Text("즐겨찾기에 저장") }
var message: Text? { Text("하트 아이콘을 탭하여 빠르게 접근할 수 있도록 항목을 유지하세요.") }

DON'T: 중요한 정보에 팁 사용

사용자는 언제든지 팁을 해제할 수 있으며 팁은 다시 나타나지 않습니다. 필수 지침이나 안전 정보를 팁에 절대 넣지 마세요.

// 틀림: 해제 가능한 팁에 중요한 정보
struct DataLossTip: Tip {
    var title: Text { Text("저장되지 않은 변경 사항이 손실됩니다") }
}

// 올바름: 중요한 정보에는 알림 또는 인라인 경고 사용
// 팁은 기능 발견 및 점진적 공개(progressive disclosure)를 위해 예약하세요

검토 체크리스트

  • Tips.configure()가 뷰가 렌더링되기 전에 App.init에서 호출되었는지 확인
  • 각 팁에 명확하고 간결한 제목이 있는지 확인 (행동 지향, 약 40자 미만)
  • 사용자가 발견한 액션을 수행할 때 팁이 무효화되는지 확인
  • 규칙이 설정되어 팁이 적시에 나타나는지 확인 (모든 팁이 첫 실행 시 즉시 나타나지 않음)
  • 하나의 뷰에 여러 팁이 있을 때 TipGroup이 사용되었는지 확인
  • 테스트 유틸리티 (showAllTipsForTesting, resetDatastore)가 #if DEBUG 뒤에 게이트되었는지 확인
  • 앱이 여러 기기를 지원하는 경우 CloudKit 동기화가 구성되었는지 확인
  • 표시 빈도가 적절하게 설정되었는지 확인 (대부분의 앱의 경우 .daily 또는 .weekly)
  • 팁이 기능 발견에만 사용되고 중요한 정보에는 사용되지 않는지 확인
  • 기본 스타일이 앱 디자인과 일치하지 않는 경우 사용자 정의 TipViewStyle이 일관되게 적용되었는지 확인
  • 팁 액션이 처리되고 액션 핸들러에서 팁이 무효화되는지 확인
  • 이벤트 기부가 올바른 사용자 액션 지점에 배치되었는지 확인
  • 사용자 정의 Tip 유형이 Sendable인지 확인하고, @MainActor에서 Tips를 구성하세요.

참고 자료

  • 완전한 구현 패턴 (사용자 정의 스타일, 이벤트 기반 규칙, 팁 그룹, 테스트 전략, 온보딩 플로우 및 SwiftUI 미리보기 구성 포함)은 references/tipkit-patterns.md를 참조하세요.

Individual skills in this repo

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

JordanCoin/ios-skills-collection

Interact with GitHub using the `gh` CLI. Use `gh issue`, `gh pr`, `gh run`, and `gh api` for issues, PRs, CI runs, and advanced queries. Use when the user asks about GitHub issues, pull requests, workflows, or wants to interact with GitHub repositories from the command line — including tasks like check CI status, create PR, list issues, or query the GitHub API.

JordanCoin/ios-skills-collection

Create media playback experiences using AVKit. Use when adding video players with AVPlayerViewController, enabling Picture-in-Picture, routing media with AirPlay, using SwiftUI VideoPlayer views, configuring transport controls, displaying subtitles and closed captions, or integrating AVFoundation playback with system UI.

JordanCoin/ios-skills-collection

Integrate and optimize Core ML models in iOS apps for on-device machine learning inference. Covers model loading (.mlmodelc, .mlpackage), predictions with auto-generated classes and MLFeatureProvider, compute unit configuration (CPU, GPU, Neural Engine), MLTensor, VNCoreMLRequest, MLComputePlan, multi-model pipelines, and deployment strategies. Use when loading Core ML models, making predictions, configuring compute units, or profiling model performance.

JordanCoin/ios-skills-collection

Implement, review, or improve maps and location features in iOS/macOS apps using MapKit and CoreLocation. Use when working with Map views, annotations, markers, polylines, user location tracking, geocoding, reverse geocoding, search/autocomplete, directions and routes, geofencing, region monitoring, CLLocationUpdate async streams, or location authorization flows. Also use when working with maps, coordinates, addresses, places, directions, distance calculations, or location-based features in Swift apps.

JordanCoin/ios-skills-collection

Display and manipulate PDF documents using PDFKit. Use when embedding PDFView to show PDF files, creating or modifying PDFDocument instances, adding annotations (highlights, notes, signatures), extracting text with PDFSelection, navigating pages, generating thumbnails, filling PDF forms, or wrapping PDFView in SwiftUI.

JordanCoin/ios-skills-collection

When the user wants to optimize their Google Play Store listing — title, short description, full description, keywords, ratings, or Play Store-specific features. Use when the user mentions "Google Play", "Android", "Play Store", "Play Console", "short description", "full description indexed", "Google Play ASO", or wants Google Play-specific keyword, creative, or ratings strategy. For iOS App Store optimization, see aso-audit and metadata-optimization.

JordanCoin/ios-skills-collection

When the user wants to implement, optimize, or use App Clips for app discovery and conversion. Use when the user mentions "App Clip", "app clip code", "mini app", "instant app", "App Clip card", "App Clip link", "no download required", "instant experience", or wants to understand how App Clips appear in App Store search. For general App Store discoverability, see aso-audit. For marketing campaigns, see ua-campaign.

JordanCoin/ios-skills-collection

When the user wants to plan a launch strategy for a new app or major update. Also use when the user mentions "app launch", "launch plan", "launch checklist", "pre-launch", "launch day", or "how to launch my app". For ongoing ASO after launch, see aso-audit. For paid acquisition during launch, see ua-campaign.

JordanCoin/ios-skills-collection

When the user wants to analyze their own app's actual performance data from App Store Connect — real downloads, revenue, IAP, subscriptions, trials, or country breakdowns synced via Appeeky Connect. Use when the user asks about "my downloads", "my revenue", "how is my app performing", "ASC data", "sales and trends", "my subscription numbers", "App Store Connect metrics", or wants to compare periods or top markets. For third-party app estimates, see app-analytics. For subscription analytics depth, see monetization-strategy.

JordanCoin/ios-skills-collection

When the user wants a full ASO health audit, review their App Store listing quality, or diagnose why their app isn't ranking. Also use when the user mentions "ASO audit", "ASO score", "why am I not ranking", "listing review", or "optimize my app store page". For keyword-specific research, see keyword-research. For metadata writing, see metadata-optimization.

JordanCoin/ios-skills-collection

Always use when working on any iOS, macOS, Swift, SwiftUI, Xcode, or Apple platform project. Routes to the correct specialized skills based on development phase and task context. This collection contains 210 skills from 28 authors covering the full iOS lifecycle.

관련 스킬