首页 > 解决方案 > SwiftUI:观察@Environment 属性变化

问题描述

我试图使用 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)
    }
}

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

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

extension EnvironmentValues {
    var intGenerator: IntGenerator {
        get {
            return self[IntGeneratorKey.self]
        }
        set {
            self[IntGeneratorKey.self] = newValue
        }
    }
}

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

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

    var body: some View {
        Text("\(intGenerator.newValue)")
    }
}

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

标签: iosswiftswiftui

解决方案


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

@Environment(\.intGenerator) var intGenerator: IntGenerator

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

并且所有的作品...用 Xcode 11.2 / iOS 13.2 测试


推荐阅读