观察核心数据对象的视图没有更新
Views observing a Core Data object are not updating
我在 ContentView
上有一个名为 Config
的核心数据对象。
这个对象是这样创建的:
@ObservedObject private var config = Config.with(PersistenceController.shared.context)!
config
有 3 个布尔属性:turnedOn
、isSoft
和 willAppear
.
turnedON
和 willAppear
的创建方式是,如果 turnedON
是 true
,则 willAppear
必须是 false
,反之亦然相反。
现在我将 config
传递给 3 个拨动开关,让用户调整每一个,真或假,但请记住,如果用户转动 turnedON
true
、willAppear
必须是 false
,反之亦然。如果用户变成 willAppear
true
,情况也是如此,因为 turnedON
必须切换到 false
,反之亦然。
所以我将配置传递给 ContentView
上的拨动开关:
CustomToggle("Turn it on?"),
config,
coreDataBooleanPropertyName:"turnedOn")
CustomToggle("Is it soft?"),
config,
coreDataBooleanPropertyName:"isSoft")
CustomToggle("Will it appear?"),
config,
coreDataBooleanPropertyName:"willAppear")
这是CustomToggle
...
导入 SwiftUI
导入核心数据
struct CustomToggle: View {
@State private var status:Bool
private let title: String
private let coreDataBooleanPropertyName:String
@ObservedObject private var config:Config {
didSet {
switch coreDataBooleanPropertyName {
case "isSoft":
self.status = config.isSoft
case "turnedOn":
self.status = config.turnedOn
case "willAppear":
self.status = config.willAppear
default:
break
}
}
}
init(_ title:String,
_ config:Config,
coreDataBooleanPropertyName:String) {
self.title = title
self.config = config
self.coreDataBooleanPropertyName = coreDataBooleanPropertyName
self.status = defaultStatus
switch coreDataBooleanPropertyName {
case "isSoft":
self.status = config.isSoft
case "turnedOn":
self.status = config.turnedOn
case "willAppear":
self.status = config.willAppear
default:
break
}
}
var body: some View {
Toggle(isOn: $status, label: {
ControlTitle(title)
})
.toggleStyle(CheckboxStyle())
.onChange(of: status, perform: { newStatus in
switch coreDataBooleanPropertyName {
case "isSoft":
config.isSoft = newStatus
case "turnedOn":
config.turnedOn = newStatus
config.willAppear = !newStatus
case "willAppear":
config.willAppear = newStatus
config.turnedOn = !newStatus
default:
return
}
let coreDataContext = PersistenceController.shared.context
do {
try coreDataContext.save()
}
catch let error{
print(error.localizedDescription)
}
})
struct CheckboxStyle: ToggleStyle {
func makeBody(configuration: Self.Configuration) -> some View {
return HStack {
Image(systemName: configuration.isOn ? "checkmark.circle.fill" : "circle")
.resizable()
.frame(width: 24, height: 24)
.foregroundColor(configuration.isOn ? Color.from("ffba00") : .gray)
.font(.system(size: 20, weight: .bold, design: .default))
.onTapGesture {
configuration.isOn.toggle()
}
configuration.label
Spacer()
}
}
}
我已经测试了核心数据条目 config
,它工作正常,但是切换开关 willAppear
和 turnedOn
在选择一个或另一个时不会更新。
我错过了什么?
而不是 didSet
,如果对象的 属性 发生变化,它不会触发,您可以通过 objectWillChange
观察它的变化(同时注意内联注释):
Toggle(isOn: $status, label: {
ControlTitle(title)
})
.onReceive(config.objectWillChange) { _ in
//run the code from your didSet here
//note that you *may* need to use something like DispatchQueue.main.async { } in here to get the updated values of the object since the values may not be updated until the next run loop -- I'm unsure of how this will behave with CoreData objects
}
.onChange(of: status, perform: { newStatus in
//etc
我在 ContentView
上有一个名为 Config
的核心数据对象。
这个对象是这样创建的:
@ObservedObject private var config = Config.with(PersistenceController.shared.context)!
config
有 3 个布尔属性:turnedOn
、isSoft
和 willAppear
.
turnedON
和 willAppear
的创建方式是,如果 turnedON
是 true
,则 willAppear
必须是 false
,反之亦然相反。
现在我将 config
传递给 3 个拨动开关,让用户调整每一个,真或假,但请记住,如果用户转动 turnedON
true
、willAppear
必须是 false
,反之亦然。如果用户变成 willAppear
true
,情况也是如此,因为 turnedON
必须切换到 false
,反之亦然。
所以我将配置传递给 ContentView
上的拨动开关:
CustomToggle("Turn it on?"),
config,
coreDataBooleanPropertyName:"turnedOn")
CustomToggle("Is it soft?"),
config,
coreDataBooleanPropertyName:"isSoft")
CustomToggle("Will it appear?"),
config,
coreDataBooleanPropertyName:"willAppear")
这是CustomToggle
...
导入 SwiftUI 导入核心数据
struct CustomToggle: View {
@State private var status:Bool
private let title: String
private let coreDataBooleanPropertyName:String
@ObservedObject private var config:Config {
didSet {
switch coreDataBooleanPropertyName {
case "isSoft":
self.status = config.isSoft
case "turnedOn":
self.status = config.turnedOn
case "willAppear":
self.status = config.willAppear
default:
break
}
}
}
init(_ title:String,
_ config:Config,
coreDataBooleanPropertyName:String) {
self.title = title
self.config = config
self.coreDataBooleanPropertyName = coreDataBooleanPropertyName
self.status = defaultStatus
switch coreDataBooleanPropertyName {
case "isSoft":
self.status = config.isSoft
case "turnedOn":
self.status = config.turnedOn
case "willAppear":
self.status = config.willAppear
default:
break
}
}
var body: some View {
Toggle(isOn: $status, label: {
ControlTitle(title)
})
.toggleStyle(CheckboxStyle())
.onChange(of: status, perform: { newStatus in
switch coreDataBooleanPropertyName {
case "isSoft":
config.isSoft = newStatus
case "turnedOn":
config.turnedOn = newStatus
config.willAppear = !newStatus
case "willAppear":
config.willAppear = newStatus
config.turnedOn = !newStatus
default:
return
}
let coreDataContext = PersistenceController.shared.context
do {
try coreDataContext.save()
}
catch let error{
print(error.localizedDescription)
}
})
struct CheckboxStyle: ToggleStyle {
func makeBody(configuration: Self.Configuration) -> some View {
return HStack {
Image(systemName: configuration.isOn ? "checkmark.circle.fill" : "circle")
.resizable()
.frame(width: 24, height: 24)
.foregroundColor(configuration.isOn ? Color.from("ffba00") : .gray)
.font(.system(size: 20, weight: .bold, design: .default))
.onTapGesture {
configuration.isOn.toggle()
}
configuration.label
Spacer()
}
}
}
我已经测试了核心数据条目 config
,它工作正常,但是切换开关 willAppear
和 turnedOn
在选择一个或另一个时不会更新。
我错过了什么?
而不是 didSet
,如果对象的 属性 发生变化,它不会触发,您可以通过 objectWillChange
观察它的变化(同时注意内联注释):
Toggle(isOn: $status, label: {
ControlTitle(title)
})
.onReceive(config.objectWillChange) { _ in
//run the code from your didSet here
//note that you *may* need to use something like DispatchQueue.main.async { } in here to get the updated values of the object since the values may not be updated until the next run loop -- I'm unsure of how this will behave with CoreData objects
}
.onChange(of: status, perform: { newStatus in
//etc