SwiftUI:观察@Environment 属性变化

sup*_*cio 13 ios swift swiftui

我试图使用 SwiftUI@Environment属性包装器,但我无法使其按预期工作。请帮助我理解我做错了什么。

例如,我有一个每秒生成一个整数的对象:

class IntGenerator: ObservableObject {
    @Published var newValue = 0 {
        didSet {
            print(newValue)
        }
    }

    private var toCanc: AnyCancellable?

    init() {
        toCanc = Timer.TimerPublisher(interval: 1, runLoop: .main, mode: .default)
            .autoconnect()
            .map { _ in Int.random(in: 0..<1000) }
            .assign(to: \.newValue, on: self)
    }
}
Run Code Online (Sandbox Code Playgroud)

这个对象按预期工作,因为我可以看到控制台日志上生成的所有整数。现在,假设我们希望这个对象是一个可以从整个应用程序和任何人访问的环境对象。让我们创建相关的环境键:

struct IntGeneratorKey: EnvironmentKey {
    static let defaultValue = IntGenerator()
}

extension EnvironmentValues {
    var intGenerator: IntGenerator {
        get {
            return self[IntGeneratorKey.self]
        }
        set {
            self[IntGeneratorKey.self] = newValue
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

现在我可以像这样访问这个对象(例如从视图中):

struct TestView: View {
    @Environment(\.intGenerator) var intGenerator: IntGenerator

    var body: some View {
        Text("\(intGenerator.newValue)")
    }
}
Run Code Online (Sandbox Code Playgroud)

不幸的是,尽管它newValue是一个@Published属性,但我没有收到有关该属性的任何更新,并且Text始终显示 0。我确定我在这里遗漏了一些东西,这是怎么回事?谢谢。

Asp*_*eri 18

Environment使您可以访问存储在EnvironmentKey其下的内容,但不会为其内部生成观察者(即,如果 EnvironmentKey 的值本身发生变化,您将收到通知,但在您的情况下,它是实例,其存储在键下的引用未更改)。所以它需要手动观察,你那里有发布者,如下所示

@Environment(\.intGenerator) var intGenerator: IntGenerator

@State private var value = 0
var body: some View {
    Text("\(value)")
        .onReceive(intGenerator.$newValue) { self.value = $0 }
}
Run Code Online (Sandbox Code Playgroud)

和所有作品......用Xcode 11.2 / iOS 13.2测试

  • Apple 如何为其“colorScheme”、“horizo​​ntalSizeClass”等事件实现此目的? (2认同)