如何注意到核心数据处理的托管对象实体的变化?
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
}
}
没有更多的比较来找出哪个是什么。 :-)
动机是在实体值发生变化时触发重新计算。
我在下面引用的快速解决方案有效,但也有缺点。这是低效的。
在实际的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
}
}
没有更多的比较来找出哪个是什么。 :-)