View protocol is not isolated on main actor, only its body property, unless you are using custom View protocol marked with @MainActor which shadows SwiftUI.View version. In that case your static property is isolated on main actor, and if you try accessing it from different isolation, it will require to be marked with await since access to it is isolated to main actor.
This constants could be safe to access without isolation if you detach them from the view:
struct TrimUIConstants {
static let thumbnailHeight: CGFloat = 70
static let thumbnailSidePadding: CGFloat = 100
}
I kinda figured it out.
This is triggered by having an @ObservableObject in the view
It's absurd and broken to me that adding a variable transforms the entire struct to @MainActor - but it seems so.
I'm still not clear why accessing a class constant isn't a safe operation though.
The value is literally inline-able, it shouldn't be a concurrency failure...
As you suggest, it seems the properties are getting isolated to an Actor, most likely the @MainActor. Based on the code sample you posted, I don't quite understand why.
Another likely workaround would be to use the nonisolated keyword on the properties.
struct TrimView: View {
nonisolated static let thumbnailHeight: CGFloat = 70
nonisolated static let thumbnailSidePadding: CGFloat = 100
}
There are too few information you've provided to figure out what in your case causes this behaviour. But more likely using @StateObject / @ObservedObject in a view causes actor isolation to be extended to the whole view, I thought that inference has been removed by default with proposal. (wrong take here)
swift-driver version: 1.90.11.1 Apple Swift version 5.10 (swiftlang-5.10.0.13 clang-1500.3.9.4)
Re actor isolation, if I take out the @ObservedObject, the problem goes away - so I'm pretty certain the @ObservedObject is causing the isolation issue.
Also interesting - the error only happens within a Task context.
class Foo:ObservableObject {
func bar() {
//This is fine
print("\(ContentView.const)")
let task = Task {
//This generates a warning
print("\(ContentView.const)")
}
}
}
because - sure - swift doesn't need to make sense!
That was/is a strange behaviour indeed. One note on overall view isolation - I recommend isolate SwiftUI views on main actor entirely by default:
@MainActor
struct MyView: View {
// ...
}
I still don't understand what was the driver for Apple engineers not to make View protocol isolated initially, but providing such isolation on your views helps to get more consistent behaviour and much less surprises.
Yeah, this still puzzles me. I'm generally against requiring whole-type isolation on protocols, because it's usually the wrong thing to do practically and semantically, but in this case the only types that can possibly conform to View are structs, so (IMO) it is actually reasonable to require @MainActor.
Although, you'd still run into [what I believe is] a design flaw whereby you don't need to [re]state the @MainActor on your conforming type, making it too hidden that the type has that restriction. So in effect you should be writing @MainActor on your views irrespective of whether View requires it.