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