Files
2nd/10_Wiki/Topics/Coding/iOS_TipKit_Patterns.md
T
2026-05-09 21:08:02 +09:00

4.4 KiB

id, title, category, status, source_trust_level, verification_status, created_at, updated_at, tags, tech_stack, applied_in, aliases
id title category status source_trust_level verification_status created_at updated_at tags tech_stack applied_in aliases
ios-tipkit-patterns TipKit — 사용자 onboarding tip Coding draft B conceptual 2026-05-09 2026-05-09
ios
tipkit
onboarding
vibe-coding
language applicable_to
Swift / SwiftUI
iOS
TipKit
popoverTip
TipView
hint
contextual help

TipKit (iOS 17+)

Apple 공식 onboarding / hint 프레임워크. 선언형 + rule-based. 한 번 본 tip 자동 추적, 빈도 제한, A/B 가능. 이전 자체 popup 보다 깔끔.

📖 핵심 개념

  • Tip protocol: title + message + image + actions.
  • Rule: 표시 조건 (parameter / event).
  • popoverTip / TipView: 표시 위치.
  • 자동 dismiss / 빈도 제한.

💻 코드 패턴

Tip 정의

import TipKit

struct FavoriteTip: Tip {
    var title: Text { Text("Save your favorites") }
    var message: Text? { Text("Tap the heart to save items.") }
    var image: Image? { Image(systemName: "heart") }
}

App startup configure

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

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

popoverTip (anchor)

struct ItemRow: View {
    let tip = FavoriteTip()

    var body: some View {
        HStack {
            Text("Item")
            Spacer()
            Image(systemName: "heart")
                .popoverTip(tip)
                .onTapGesture {
                    tip.invalidate(reason: .actionPerformed)
                    // 사용했으니 다시 안 띄움
                }
        }
    }
}

TipView (inline)

TipView(WelcomeTip())
    .padding()

Rule (parameter)

struct SearchTip: Tip {
    @Parameter static var hasSearched: Bool = false

    var rules: [Rule] {
        #Rule(SearchTip.$hasSearched) { $0 == false }
        // 사용자가 한 번도 search 안 했을 때만
    }

    var title: Text { Text("Try search") }
}

// 검색 발생 시
SearchTip.hasSearched = true

Rule (event)

struct LongTapTip: Tip {
    static let didLongTap = Event(id: "didLongTap")

    var rules: [Rule] {
        #Rule(Self.didLongTap) { $0.donations.count >= 3 }
        // 3번 길게 탭한 후 표시
    }

    var title: Text { Text("Try Quick Action") }
    var message: Text? { Text("Long press for shortcuts") }
}

// 탭 발생 시
Task { await LongTapTip.didLongTap.donate() }

Action (CTA)

struct UpgradeTip: Tip {
    var actions: [Action] {
        Action(id: "upgrade", title: "Upgrade")
        Action(id: "later", title: "Later")
    }

    var title: Text { Text("Go Pro") }
}

// 처리
.popoverTip(tip) { action in
    switch action.id {
    case "upgrade": showUpgrade = true
    case "later": tip.invalidate(reason: .actionPerformed)
    default: break
    }
}

Frequency / 빈도

try? Tips.configure([
    .displayFrequency(.immediate),     // 모든 tip 즉시
    // .displayFrequency(.daily)        // 하루 1개만
    // .displayFrequency(.hourly)       // 시간당 1개
])

특정 tip 만 다른 빈도:

struct BigTip: Tip {
    var options: [Option] {
        Tips.MaxDisplayCount(3)         // 최대 3번
        Tips.IgnoresDisplayFrequency(true) // 글로벌 무시
    }
}

Reset (테스트)

try? Tips.resetDatastore()
FavoriteTip().invalidate(reason: .actionPerformed)

🤔 의사결정 기준

상황 추천
iOS 17+ TipKit
다양한 OS 자체 popover + UserDefaults
강력 onboarding (3-step) OnboardingView 직접
Contextual hint TipKit popoverTip
Marketing modal App Store 권장 X (자체 sheet)

안티패턴

  • TipKit configure 안 함: tip 안 보임.
  • Invalidate 누락: 영원 보임.
  • Tip 너무 많음: 사용자 피로. priority + frequency.
  • Tip 이 광고: Apple 가이드 위반. 진짜 hint 만.
  • Modal 같은 거대 tip: 작은 popover 만.
  • Reset 없음 (dev): 디버깅 시 다시 못 봄.
  • Rule 복잡: 디버깅 어려움. 단순.

🤖 LLM 활용 힌트

  • iOS 17+ = TipKit.
  • Tip + Rule (parameter / event) + Frequency 3종.
  • Reset 으로 dev cycle.

🔗 관련 문서