I tried this post https://www.swiftbysundell.com/articles/building-an-async-swiftui-button/ where the code is from but have added the priority constant in the struct. The Button is doing what it should be (only show the ProgressView when the sleep time is over and then only so long until the action is done) if I use the priority of .utility but not if I use .userInitiated. Why is that? Shouldn't both be cancelled by the .cancel() function before the showProgressView = true statement gets fired?
When tapping on the button ".userInitiated" the console output is:
- task cancelled
- task created
video: https://i.stack.imgur.com/zhsnQ.jpg
struct ContentView: View{
@State var count = 0
@State var showProg = false
func heavyTask() async throws ->Int{
var k = count
for _ in 0..<5_000_000{
k += 1
}
return k
}
var body: some View{
VStack{
AsyncButton(action: {try? await count = heavyTask()},actionOptions: [.showProgressView], label: {
Text(".utility")
}, priority: .utility)
AsyncButton(action: {try? await count = heavyTask()},actionOptions: [.showProgressView], label: {
Text(".userInitiated")
}, priority: .userInitiated)
Text("result: \(count)")
}
}
}
struct AsyncButton<Label: View>: View {
var action: () async -> Void
var actionOptions = Set(ActionOption.allCases)
@ViewBuilder var label: () -> Label
let priority: TaskPriority
@State private var isDisabled = false
@State private var showProgressView = false
var body: some View {
Button(
action: {
if actionOptions.contains(.disableButton) {
isDisabled = true
}
Task {
var progressViewTask: Task<Void, Error>?
if actionOptions.contains(.showProgressView) {
progressViewTask = Task(priority: priority) {
try await Task.sleep(nanoseconds: 900_000_000)
showProgressView = true
print("task created")
}
}
await action()
progressViewTask?.cancel()
print("task cancelled")
isDisabled = false
showProgressView = false
}
},
label: {
ZStack {
label().opacity(showProgressView ? 0 : 1)
if showProgressView {
ProgressView()
}
}
}
)
.disabled(isDisabled)
}
}
extension AsyncButton {
enum ActionOption: CaseIterable {
case disableButton
case showProgressView
}
}