EnvironmentKey 的 Swift 6 并发问题

问题描述 投票:0回答:1

我有一个相当简单的构造,在我尝试将 Swift 语言版本切换到 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 }
    }
}

现在似乎存在一个关于

defaultValue
的问题:无法从非隔离上下文中引用主要参与者隔离类属性“main”。 显然,
EnvironmentKey
协议要求它是
nonisolated
以维护协议一致性。

我花了几个小时与 ChatGPT 和 Copilot 一起尝试找到解决此问题的并发安全方法,但到目前为止还没有运气。我在这里缺少什么?我正在寻找在 Swift 6 中执行此操作的正确方法以及任何允许我推迟修复它的解决方法,但仍将其余代码库迁移到 Swift 6。

最终该值用于 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)
        }
    }
}

这是继承的代码,我正在尝试迁移 - 我不是 SwiftUI 的专家,我什至不确定他们试图在这里完成什么。但也许答案是找到一种完全不同的方法......

swift concurrency swift-concurrency swift6
1个回答
0
投票

如果您总是使用

.environment(\.someHeight, proxy.size.height)
设置环境值,则默认值并不重要,因此您可以将其设置为某个常量值:

static let defaultValue: CGFloat = 0

在 Xcode 16 中,您还可以删除

SomeHeightKey
并直接使用
Entry
扩展中的
EnvironmentValues
宏:

extension EnvironmentValues {
    @Entry var someHeight: CGFloat = 0
}

如果您确实需要使用主要参与者隔离值作为环境键的默认值,您可以将其设置为视图层次结构根部的环境值。

var body: some Scene {
    WindowGroup {
        ContentView()
    }
    .environment(\.someKey, someMainActorIsolatedValue)
}

但我不会用

UIScreen.main.bounds.height
这样做。如果您需要知道视图有多少可用空间,请使用如您所示的
GeometryReader
。大多数时候,您甚至不需要几何阅读器,因为还有许多其他修改器可以帮助您布局视图,例如
containerRelativeFrame

© www.soinside.com 2019 - 2024. All rights reserved.