My app is iOS 16+. For all iOS 17+ users I would like to use TipKit to show usage hints.
Based on some tutorials I created the following setup using a dummy protocol to be able to use popupTip without iOS 16 compile errors (see below)
While this works in general, tips are shown multiple times. However, if I understand the Apple docs correctly, this should not happen. Each tip should be shown only once.
However, when using more than one tip, the last tip is shown over and over again as soon as the corresponding view becomes visible (without using resetDatastore()).
Is this due to my setup using the dummy protocol? Or am I doing something wrong in general?
Full setup:
/// Protocol for ensuring compatibility.
/// Enables tips to be passed and stored as properties without availability issues.
@available(iOS, obsoleted: 17, message: "This will be removed once we only support iOS 17+")
public protocol TipSupport {
@available(iOS 17, *)
var tip: AnyTip { get }
}
@available(iOS 17, *)
public extension Tip where Self: TipSupport {
var tip: AnyTip { AnyTip(self) }
}
public extension View {
/// Helper for making the `popupTip` modifier available for iOS <17.
@available(iOS, obsoleted: 17, message: "Can be removed once we only support iOS 17+")
@ViewBuilder func popupTip(_ tipSupport: TipSupport?, arrowEdge: Edge = .top) -> some View {
if #available(iOS 17, *), let tip = tipSupport?.tip {
self.popoverTip(tip, arrowEdge: arrowEdge)
} else {
self
}
}
}
Now I can use tips in my code:
struct TipTestView: View {
var body: some View {
Text("Hello, World!")
.popupTip(SampleTip())
}
}
struct SampleTip: Tip, TipSupport {
var id: String { "SampleTip" }
var title: Text {
Text("Some Title")
}
var message: Text? {
Text("More information")
}
var image: Image? {
Image(systemName: "hand.tap")
}
}
TipKit is configured in my app setup:
.task {
if #available(iOS 17, *) {
#if DEBUG
//try? Tips.resetDatastore()
#endif
try? Tips.configure([
.datastoreLocation(.applicationDefault),
.displayFrequency(.immediate)
])
}
}