I hav a fairly simple construct, that has worked fine up until I tried to switch Swift language version to 6.0:
private struct SomeHeightKey: EnvironmentKey {
static var defaultValue: CGFloat { UIScreen.main.bounds.size.height }
}
public extension EnvironmentValues {
var someHeight: CGFloat {
get { self[SomeHeightKey.self] }
set { self[SomeHeightKey.self] = newValue }
}
}
Now there seems to be an issue about defaultValue: Main actor-isolated class property 'main' can not be referenced from a nonisolated context.
And apparently the EnvironmentKey protocol requires it to be nonisolated to uphold protocol conformance.
I have spent hours with ChatGPT and Copilot trying to find a concurrency safe way around this, but no luck so far. What am I missing here? I am both looking for the correct way of doing this in Swift 6 as well as any workaround that will allow me to postpone fixing it, but still migrate the rest of the codebase to Swift 6.
Ultimately the value is used for a ScrollViewWrapper:
public struct ScrollViewWrapper<Content: View>: View {
let content: () -> Content
public init(@ViewBuilder _ content: @escaping () -> Content) {
self.content = content
}
public var body: some View {
GeometryReader { proxy in
ScrollView {
content().frame(minHeight: proxy.size.height)
}
.frame(height: proxy.size.height)
.environment(\.someHeight, proxy.size.height)
}
}
}
This is inherited code, that I am trying to migrate - not being an expert in SwiftUI, I am not even sure what they were trying to accomplish here. But perhaps the answer is to find a different way of doing this altogether...
If you are always setting the environment value with .environment(\.someHeight, proxy.size.height), the default value doesn't really matter, so you can just set it to some constant value:
static let defaultValue: CGFloat = 0
In Xcode 16, you can also remove SomeHeightKey and use the Entry macro in the EnvironmentValues extension directly:
extension EnvironmentValues {
@Entry var someHeight: CGFloat = 0
}
If you do need to use a main actor isolated value as the default value of an environment key, you can set that as the environment value at the root of your view hierarchy.
var body: some Scene {
WindowGroup {
ContentView()
}
.environment(\.someKey, someMainActorIsolatedValue)
}
But I wouldn't do this with UIScreen.main.bounds.height. If you need to know how much space is available for a view, use a GeometryReader like you have shown. And most of the time you don't even need a geometry reader, since there are many other modifiers that help you layout views, like containerRelativeFrame.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With