Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save CraigSiemens/273a9b7376bc882b383aa62764ee8bae to your computer and use it in GitHub Desktop.
Save CraigSiemens/273a9b7376bc882b383aa62764ee8bae to your computer and use it in GitHub Desktop.
A view modifier that allows `.refreshable` to work reliably alongside state updates that would otherwise cause the refresh task to be cancelled.
extension View {
/// A view modifier that allows `.refreshable` to work reliably alongside state updates
/// that would otherwise cause the refresh task to be cancelled.
///
/// In SwiftUI, when a state change triggers a view redraw, any ongoing `.refreshable` task is
/// cancelled. This can be problematic if your refresh action or scrolling also updates state.
///
/// - Important:
/// `.refreshable` remains the preferred view modifier. Use this modifier only if your view
/// experiences unexpected task cancellations, as a workaround for this specific issue.
///
/// - Parameter action: The async action to perform when a refresh is triggered.
func refreshableWhileUpdatingState(action: @escaping () async -> Void) -> some View {
modifier(RefreshableWhileUpdatingState(action: action))
}
}
private struct RefreshableWhileUpdatingState: ViewModifier {
typealias RefreshId = RefreshableWhileUpdatingStateRefreshId
@State private var refreshId: RefreshId?
let action: () async -> Void
func body(content: Content) -> some View {
content
.refreshable {
await withCheckedContinuation {
refreshId = .init(continuation: $0)
}
}
.task(id: refreshId) {
guard refreshId != nil else { return }
await action()
refreshId?.continuation.resume()
refreshId = nil
}
}
}
private struct RefreshableWhileUpdatingStateRefreshId {
private let id: UUID = .init()
let continuation: CheckedContinuation<Void, Never>
}
extension RefreshableWhileUpdatingStateRefreshId: Hashable {
static func == (lhs: Self, rhs: Self) -> Bool {
lhs.id == rhs.id
}
func hash(into hasher: inout Hasher) {
hasher.combine(id)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment