Is it considered wrong now to use forEach to operate on MainActor isolated objects?
No. But you need to make sure that the forEach
is executed in a MainActor isolated context.
I'm not sure what the issue with your code is exactly as I'm lacking the relevant context of where this function is called, but while this reproduces the warning in a Swift Playground:
@MainActor var stackView = UIStackView()
@MainActor var view1 = UIView()
@MainActor var view2 = UIView()
Task {
await [
view1,
view2
]
// WARNING: Converting function value of type '@MainActor (UIView)
// -> Void' to '(UIView) throws -> Void' loses global actor
// 'MainActor'; this is an error in the Swift 6 language mode
.forEach(stackView.addArrangedSubview)
}
Or, in a more general case:
let fooClosure: @MainActor (String) -> Void = { _ in }
// WARNING: Converting function value of type '@MainActor (String)
// -> Void' to '(String) throws -> Void' loses global actor
// 'MainActor'; this is an error in the Swift 6 language mode
["apple", "orange"].forEach(fooClosure) // â
Since forEach
will inherit the isolation context of its caller, you can fix the issue by annotating the call site to ensure you're in the correct isolation context, by any method you want. For example:
let fooClosure: @MainActor (String) -> Void = { _ in }
Task { @MainActor in
["apple", "orange"].forEach(fooClosure) // â
}
If the code that is calling this forEach
is in a function, you can annotate the entire function instead:
@MainActor func fooFunction() {
["apple", "orange"].forEach(fooClosure) // â
}
If the issue is that the forEach
was already being called in a MainActor-isolated context but the compiler isn't able to infer it (for example: a completion handler from a framework that specifies that it'll always be called on the main thread, but isn't annotated with @MainActor
yet), you can use MainActor.assumeIsolated { ... }
:
MainActor.assumeIsolated {
["apple", "orange"].forEach(fooClosure) // â
as long as this is actually called in the Main Actor
}
TL;DR: Make sure the compiler knows that the forEach
is called from the Main Actor.