TipKit decides when a tip appears through four mechanisms: invalidation when the feature gets
used, #Rule conditions on parameters, persisted event counts, and options such as a display
cap.
Invalidate a Used Tip
When the user performs the action the tip teaches, invalidate it so it never shows again.
Button("Add") {
FeedTip.add.invalidate(reason: .actionPerformed)
store.addItem()
}
.popoverTip(FeedTip.add)
Parameters and Rules
@Parameter declares state the rules can read; the #Rule macro gates the tip on it. Sync the
parameter from app state, for example in onAppear.
enum FeedTip: Tip {
@Parameter static var isPro: Bool = false
case add
var title: Text { Text("Add") }
var rules: [Rule] {
#Rule(Self.$isPro) { isPro in
isPro == true
}
}
}
.popoverTip(FeedTip.add)
.onAppear {
FeedTip.isPro = isPro
}
The rules property is a RuleBuilder, so several rules combine and all must pass.
Events
An Event is a persisted counter: donations survive app restarts, unlike parameters. Donate on
each user action and gate the tip on the count, for example "show after the third add".
static let itemAdded = Event(id: "itemAdded")
var rules: [Rule] {
#Rule(Self.itemAdded) {
$0.donations.count >= 3
}
}
Button("Add") {
Task {
await FeedTip.itemAdded.donate()
store.addItem()
}
}
Donations also filter by time window: $0.donations.donatedWithin(.week).count == 0.
Options Beat Rules
The options property caps behavior regardless of rules. With MaxDisplayCount(3) the tip never
shows a fourth time, even while every rule still passes.
var options: [any TipOption] {
MaxDisplayCount(3)
}