Reputation: 101
We are updating our app to Swift 6, and one of the fixes was to modify the following protocol extensions to start using @Sendable
.
Code:
protocol ThreadService: AnyObject {
func asyncAfter(
deadline: DispatchTime,
qos: DispatchQoS,
flags: DispatchWorkItemFlags,
execute work: @escaping @Sendable @convention(block) () -> Void
)
func sync(execute block: @Sendable () -> Void)
}
extension ThreadService {
func async(
group: DispatchGroup? = nil,
qos: DispatchQoS = .unspecified,
flags: DispatchWorkItemFlags = [],
execute work: @escaping @Sendable @convention(block) () -> Void
) {
async(group: group, qos: qos, flags: flags, execute: work)
}
func asyncAfter(
deadline: DispatchTime,
qos: DispatchQoS = .unspecified,
flags: DispatchWorkItemFlags = [],
execute work: @escaping @Sendable @convention(block) () -> Void
) {
asyncAfter(deadline: deadline, qos: qos, flags: flags, execute: work)
}
}
extension DispatchQueue: ThreadService {}
We are having the following issue with the code below:
The code:
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
isDisabled = false
}
The issue:
Main actor-isolated property 'isDisabled' can not be mutated from a Sendable closure
isDisabled is defined as follows:
@State private var isDisabled: Bool = false
Is there any way to fix this without using Task {} inside asyncAfter? The code looks weird, redundant, and difficult to read since asyncAfter is already running on the main thread (See the solution below).
We tried the following things:
1 - It works, but it looks strange. Why do we need to add the Task if it's already running on the main thread? Is there another way to fix this?
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
Task { @MainActor in
isDisabled = false
}
}
2 - We added the @MainActor keyword, but we have the same issue:
@MainActor @State private var isDisabled: Bool = false
3 - I saw this approach, it looks fine, but we want to continue using asyncAfter approach, is there a way to use the asyncAfter method without using Task within it?:
Task {
try await Task.sleep(nanoseconds: 500_000_000) // 0.5 seconds
isDisabled = false
}
Upvotes: 0
Views: 179