I am using .task
to fetch some data when entering a new view. I do this till it gets the data. This works fine if the call really returns the right data, if not and I close the view, I get an endless loop. This is my code:
VStack(){
Form{
Section("QR-Code"){
if let cgImage = EFQRCode.generate(for: deviceId, watermark: UIImage(named: "LogoSmarterSoftware")?.cgImage) {
Image(uiImage: UIImage(cgImage: cgImage)).resizable().frame(width: 150, height: 150)
}
/*Button("Login"){
//deviceId = "0B6B03F3-99E1-469F-BE1E-EA163EFE0963"
}*/
}
}.frame(height: 180)
}.task {
users.removeAll()
if (deviceId == "") {
deviceId = x // Could change here
}
userId = ""
employeeId = ""
/*Task{
await doHTTPUserCall()
}*/
while userId.isEmpty || employeeId.isEmpty{
Task{
await doHTTPUserCall()
}
print("test")
do{
try await Task.sleep(nanoseconds: 3_000_000_000)
} catch {
print(error)
}
//deviceId = "0B6B03F3-99E1-469F-BE1E-EA163EFE0963"
}
}
If I exit the view without getting a right response, I get an endless loop saying
CancellationError() test
CancellationError() test
CancellationError() test
CancellationError() test
Is there any way of killing an existing task or am I missing something in my code?
CodePudding user response:
There is endless loop there. When view disappears task is cancelled, but cancelation handling is on our side
According to doc:
so it is needed at least to verify state, like
while !Task.isCancelled && (userId.isEmpty || employeeId.isEmpty) {
or call checkCancellation
inside loop wrapping everything in try/catch
while userId.isEmpty || employeeId.isEmpty {
try Task.checkCancellation()
CodePudding user response:
The problem is your while
loop, which catches the thrown error prints it, and then proceeds, effectively ignoring the error after it prints it:
while userId.isEmpty || employeeId.isEmpty{
Task{
await doHTTPUserCall()
}
print("test")
do{
try await Task.sleep(nanoseconds: 3_000_000_000)
} catch {
print(error)
}
//deviceId = "0B6B03F3-99E1-469F-BE1E-EA163EFE0963"
}
Two solutions:
You can catch and rethrow the error:
while userId.isEmpty || employeeId.isEmpty{ Task{ await doHTTPUserCall() } print("test") do{ try await Task.sleep(nanoseconds: 3_000_000_000) } catch { print(error) throw error } //deviceId = "0B6B03F3-99E1-469F-BE1E-EA163EFE0963" }
Don’t catch the error at all:
while userId.isEmpty || employeeId.isEmpty{ Task{ await doHTTPUserCall() } print("test") try await Task.sleep(nanoseconds: 3_000_000_000) //deviceId = "0B6B03F3-99E1-469F-BE1E-EA163EFE0963" }