struct TrimView: View {
static let thumbnailHeight: CGFloat = 70
static let thumbnailSidePadding: CGFloat = 100
My property is simple. Defined in my struct.
But when I want to access it elsewhere...
Presumably - TrimView is inheriting @MainActor from the View protocol.
But:
- I can't see anywhere in the docs that say View inherits @MainActor
- It's a static class constant. It's immutable by definition. Surely this is safe???
What's going on here?
1 Like
vns
2
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...
Minimal reproduction case
struct ContentView: View {
@ObservedObject var vm = Foo()
static let const:CGFloat = 100
var body: some View {
Text("Hello")
}
}
class Foo:ObservableObject {
func bar() {
let task = Task {
print("\(ContentView.const)")
}
}
}
1 Like
AronL
(Aron Lindberg)
4
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
}
vns
5
1 Like
vns
6
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)
vns
7
My bad - its hidden behind the feature flag: -enable-upcoming-feature DisableOutwardActorInference
cc @ConfusedVorlon
1 Like
No problem with workarounds - I can sort that.
Just interested in the wierd behaviour.
XCode 15.3
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!
I provided the entire code and xcode version 
vns
10
Oh, sorry, I've confused who is topic starter, sleepless night 
1 Like
vns
11
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.
3 Likes
I hate all the implicit isolation regimes.
There is just way too much going on that is hidden from view!
I much prefer explicit annotations.