如何注意到核心数据处理的托管对象实体的变化?

How to notice changes on Managed Object Entity handled by Core Data?

动机是在实体值发生变化时触发重新计算。

我在下面引用的快速解决方案有效,但也有缺点。这是低效的。

在实际的App中,有几十个实体。对其中任何一个的更改都会导致不必要的通知。如果可能的话,这些是可以避免的。

在此示例中,只有 EmployeeMO 感兴趣。不需要观察其他实体。

你有什么想法?

let n = NotificationCenter.default
n.addObserver(self, selector: #selector(mocDidChange(notification:)),
              name: NSNotification.Name.NSManagedObjectContextObjectsDidChange,
              object: managedObjectContext)

@objc func mocDidChange(notification n: Notification) {
  if n.isRelatedTo(as: EmployeeMO.self) {
    // do recalculation
  }
}

以及检查通知是否与给定托管对象相关的扩展:

extension Notification {

  public func isRelatedTo<T>(as t: T.Type) -> Bool where T: NSManagedObject {

    typealias S = Set<T>

    let d = userInfo as! [String : Any]

    return d[NSInsertedObjectsKey] is S ||
      d[NSUpdatedObjectsKey] is S ||
      d[NSDeletedObjectsKey] is S ||
      d[NSRefreshedObjectsKey] is S ||
      d[NSInvalidatedObjectsKey] is S
  }

}

Xcode 9 测试版,Swift 4

谢谢。

这是一个内置对象,已经可以做到这一点 - NSFetchedResultsController。它旨在与 tableview 或 collectionView 一起使用,但没有它们也可以正常工作。它足够轻巧,可以安全地只用于一个物体。

感谢@jon,现在我的源代码有了很大的改进。

class myBaseArrayController: NSArrayController, NSFetchedResultsControllerDelegate {

  // https://developer.apple.com/documentation/coredata/nsfetchedresultscontroller
  var frc: NSFetchedResultsController<NSManagedObject>?

  func setupObserver() {
    frc = NSFetchedResultsController(fetchRequest: defaultFetchRequest() as! NSFetchRequest<NSManagedObject>,
                                     managedObjectContext: managedObjectContext!,
                                     sectionNameKeyPath: nil, cacheName: nil)
    frc?.delegate = self

    do {
      try frc?.performFetch()
    }
    catch {
      fatalError("...")
    }
  }

}

对应实体的每个 ArrayController 都简单地实现 controllerDidChangeContent().

class myOneOfThemArrayController: myBaseArrayController {

  func controllerDidChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {
    print("controllerDidChangeContent: \(controller.fetchRequest.entityName)")
    // do some work
  }

}

没有更多的比较来找出哪个是什么。 :-)