SwiftUI:观察发布对象的内部变化

时间:2020-05-10 16:23:47

标签: swiftui

SwiftUI,Swift 5.2,Xcode 11.4

我试图观察单例中的变化,但是我并不总是刷新SwiftUI视图:

final class Patient: ObservableObject {
      static var shared: Patient
      @Published var medicalData: MedicalData

      init { ... }

      final class MedicalData { 
            var allergies: String
            var ...

            init { ... }
      }
}

因此,在我的SwiftUI视图中:

struct ContentView: View {
       @ObservedObject var patient: Patient = Patient.shared
       var body: some view { ... }
}

如果任何对象替换了医疗数据,发布者将正确通知我的SwiftUI:

patient.medicalData = NEW_MEDICAL_DATA --> OK! View refreshed

但是,如果任何对象更改了当前医疗数据中的值,则不会刷新SwiftUI视图:

patient.medicalData.allergies = "Alcanfor" --> NOT PUBLISHED

有人知道如何做到这一点吗? 先感谢您。

2 个答案:

答案 0 :(得分:0)

最简单的是使其成为值类型

  struct MedicalData { 
        var allergies: String
        var ...

这给

  patient.medicalData.allergies = "Alcanfor" --> PUBLISHED

更新:CoreData对象的可能方法...我仍然希望使用struct(现在作为包装器)。它需要付出一些额外的努力,但可以控制哪些因素会影响视图刷新,而哪些不应该影响,并且刷新本身可以通过现有的发布自动运行

// helper struct wrapper
struct CoreDataWrapper<T:NSManagedObject> {
    let value: T

    init(_ wrapped: T) {
        value = wrapped
    }

    private var refreshed = false
    private mutating func refresh() {
        refreshed.toggle()
    }
}

// helper protocol of properties visible to extensions (optionals - works w/o it as well)
protocol MedicalDataProtocol {
    var allergies: String? { get set }
}

// extension to wrapper for a specific class properties
extension CoreDataWrapper: MedicalDataProtocol where T == MedicalData {
    var name: String? {
        get { value.allergies }
        set { value.allergies = newValue; refresh() }
    }
}


// usage in view model

final class Patient: ObservableObject {
      static var shared: Patient
      @Published var medicalData: CoreDataWrapper<MedicalData>

      // ... other code here

答案 1 :(得分:0)

找到了一种执行此操作的优雅方法(请参见didSet):

final class Patient: ObservableObject {
      static var shared: Patient
      @Published var medicalData = MedicalData() { 
           didSet {
                  suscription = medicalData.objectWillChange.sink { [weak self] _ in
                        self?.objectWillChange.send()
                  }
           }
      }
      var suscription: AnyCancellable?

      init { ... }
}

如果属性已初始化,则可以直接使用。如果没有,只需在初始化init()的didSet属性后再写medicalData代码。

当然,MedicalData必须符合ObservableObject协议。