[G1-Sync] Manual knowledge update

This commit is contained in:
Antigravity Agent
2026-05-09 21:08:02 +09:00
parent f0befc887a
commit 93ec7e9056
363 changed files with 68333 additions and 64 deletions
@@ -0,0 +1,189 @@
---
id: ios-tipkit-patterns
title: TipKit — 사용자 onboarding tip
category: Coding
status: draft
source_trust_level: B
verification_status: conceptual
created_at: 2026-05-09
updated_at: 2026-05-09
tags: [ios, tipkit, onboarding, vibe-coding]
tech_stack: { language: "Swift / SwiftUI", applicable_to: ["iOS"] }
applied_in: []
aliases: [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 정의
```swift
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
```swift
@main
struct MyApp: App {
init() {
try? Tips.configure([
.displayFrequency(.daily),
.datastoreLocation(.applicationDefault),
])
}
var body: some Scene {
WindowGroup { ContentView() }
}
}
```
### popoverTip (anchor)
```swift
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)
```swift
TipView(WelcomeTip())
.padding()
```
### Rule (parameter)
```swift
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)
```swift
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)
```swift
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 / 빈도
```swift
try? Tips.configure([
.displayFrequency(.immediate), // tip
// .displayFrequency(.daily) // 1
// .displayFrequency(.hourly) // 1
])
```
특정 tip 만 다른 빈도:
```swift
struct BigTip: Tip {
var options: [Option] {
Tips.MaxDisplayCount(3) // 3
Tips.IgnoresDisplayFrequency(true) //
}
}
```
### Reset (테스트)
```swift
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.
## 🔗 관련 문서
- [[iOS_SwiftUI_State_Property_Wrappers]]
- [[iOS_App_Clips]]
- [[iOS_Live_Activities]]