因此,我希望有一个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并未更新。...
答案 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
,我需要使两者保持同步,这与“单一来源真相”模式不是吗?