SwiftUI中的计算(NSObject)属性不会更新视图

时间:2019-07-31 11:13:31

标签: swift core-data swiftui computed-properties combine

因此,我希望有一个Text可以根据我的CoreData模型的内容来更改其内容。为此,我在Xcode beta 4中使用了计算属性,但是它似乎不再起作用。要么是错误,要么是我看不到其他问题?

我确切的问题是,在商店中调用self.objectWillChange.send()时,我的View(以及计算的属性)似乎没有更新。

我也试图将我的var'导出'到商店中,然后从那里得到它,结果相同...


编辑: 我只是在另一个类上尝试了同样的方法,但它不适用于objectWillChange.send(),而仅适用于@Published,但是,即使该类是从NSObject继承的,它也无法正常工作。


我刚刚发现:

struct Today: View {
    @EnvironmentObject var myStore: DateStore
    var hasPlans: Bool {
        guard let plans = myStore.getPlans() else { return false }
        return plans.isEmpty
    }

    var body: some View{
        VStack{
            Text(hasPlans ? "I have plans":"I have time today")
            Button(action: {
                self.myStore.addPlans(for: Date())
            }) {
                Text("I have plans")
            }
    }
}

class DateStore: NSObject, ObservableObject, NSFetchedResultsControllerDelegate {
    private var fetchedResultsController: NSFetchedResultsController<DateStore>
    //...
    public func addPlans(for date: Date){
        //{...}
        if let day = self.dates.first(where: { $0.date == date}){
            day.plans += 1
            saveChanges()
        }else{
            self.create(date: dayDate)
        }
    }

    func controllerDidChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {
        self.objectWillChange.send()
    }
}


这是我的问题的非常简化的版本,我知道我的DataModel可以工作,因为值发生了更改并且调用了self.objectWillChange.send(),但是由于某些原因我的View并未更新。...

3 个答案:

答案 0 :(得分:6)

我看不到NSObject是问题的根源。问题似乎在于您尚未实现objectWillChange。编译器将使您摆脱困境,但是结果是您的objectWillChange什么也不做。

这是一个简单的示例,显示了如何使用具有绑定功能的计算属性来配置ObservableObject(即NSObject):

class Thing : NSObject, ObservableObject {
    let objectWillChange = ObservableObjectPublisher()
    var computedProperty : Bool = true {
        willSet {
            self.objectWillChange.send()
        }
    }
}

struct ContentView: View {
    @EnvironmentObject var thing : Thing
    var body: some View {
        VStack {
            Button(self.thing.computedProperty ? "Hello" : "Goodbye") {
                self.thing.computedProperty.toggle()
            }
            Toggle.init("", isOn: self.$thing.computedProperty).frame(width:0)
        }
    }
}

通过点击按钮和开关,您可以看到所有内容均处于活动状态并响应视图中的绑定。

答案 1 :(得分:3)

使用我自己的代码进行实验也遇到类似的问题。

当采用ObservableObject的Class是NSObject的子类时,@ Publisher SwiftUI魔术似乎中断了。

简短的解决方案是,如果它不是NSObject的子类,则可以与@Published一起使用,然后将其设为NSObject的子类,则将@Published替换为

let objectWillChange = PassthroughSubject<Void, Never>()

您必须在您的Class文件中导入Combine框架。

这是我正在尝试的可运行应用程序中的一些代码。

视图:

import SwiftUI

struct ContentView: View {

    //Bind using @ObservedObject
    @ObservedObject var provider: Provider

    var body: some View {
        Text("\(self.provider.distance)")
    }
    ...
}

班级:

import Combine

class Provider: NSObject, ObservableObject {

    //Instead of using @Published, use objectwillchange
    //@Published var distance: CLLocationDistance = 0.0
    let objectWillChange = PassthroughSubject<Void, Never>()
    var distance = 0.0
    ...

    func calculateDistance() {
        ...
        // publish the change
        self.objectWillChange.send()
        self.distance = newDistance
    }
}

答案 2 :(得分:0)

一种有效的解决方案是简单地创建一个 new @State var而不是使用计算所得的属性。但是,根据WWDC关于SwiftUI的说法,这有点不对劲,因为我的“实际状态”存在于我的数据模型中,并且通过声明一个新的@State,我需要使两者保持同步,这与“单一来源真相”模式不是吗?

相关问题