I’m using .refreshable()
on a List
in SwiftUI. With the following code, I pull to refresh in an iOS 17.4 simulator, the spinner appears, and then goes away after a couple of seconds.
var body: some View {
List() {
// items ...
}
.refreshable { try? await Task.sleep(nanoseconds: 3_000_000_000) }
}
However, when I put my actual refresh logic into the refreshable
function, the spinner no longer goes away, even though my refresh function completes without error (which I verified using breakpoints in Xcode). Instead, the spinner just spins forever.
var body: some View {
List() {
// items ...
}
.refreshable { await query.refetchAsync() }
}
query.refetchAsync()
triggers a refetch that runs on a background Task
and then waits for an update by iterating over a NotificationCenter.notifications()
object returned by self.client.queryUpdatesAsync()
:
public func refetchAsync() async {
self.refetch()
for await update in self.client.queryUpdatesAsync() {
if update.key != self.key { continue }
switch self.dataStatus {
case .idle, .pending: continue
default: break
}
}
}
How do I fix this bug?
2
Answers
The
break
in yourswitch self.dataStatus {
breaks the switch, not the for loop. To fix that, you can use labeled statements:The only possible reason for this is your function
refetchAsync()
never finishes. You need to fix that first.As we don’t know your proper use case so assuming that in your
default
case you want to terminate the loop itself.If that is so then it should work:
If it is not your user case then the asyncSequence
self.client.queryUpdatesAsync()
is never ending due to some of your other bug in the code. Fix that also.