观察核心数据对象的视图没有更新

Views observing a Core Data object are not updating

我在 ContentView 上有一个名为 Config 的核心数据对象。

这个对象是这样创建的:

@ObservedObject private var config = Config.with(PersistenceController.shared.context)!

config 有 3 个布尔属性:turnedOnisSoftwillAppear.

turnedONwillAppear 的创建方式是,如果 turnedONtrue,则 willAppear 必须是 false,反之亦然相反。

现在我将 config 传递给 3 个拨动开关,让用户调整每一个,真或假,但请记住,如果用户转动 turnedON truewillAppear 必须是 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,它工作正常,但是切换开关 willAppearturnedOn 在选择一个或另一个时不会更新。

我错过了什么?

而不是 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