How to notice changes in the managed object processed by the underlying data?

Motivation - get a trigger for recounting when Entity values โ€‹โ€‹change.

My quick solution below works, but it has disadvantages. It is inefficient.

There are dozens of entities in the application itself. Changes to any of these will cause unnecessary notifications. They could have been avoided, if possible.

In this example, only EmployeeMO is interested. No other object needs observation.

What do you think?

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 } } 

And an extension to check if a notification is associated with this managed entity:

 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 Beta, Swift 4

Thanks.

0
source share
2 answers

This is the built-in object that does this already - NSFetchedResultsController . It is designed to work with tableview or collectionView, but it can work fine without it. It is light enough that it can only be used for one object.

+1
source

Thanks to @jon, now my source code is significantly improved.

 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("...") } } } 

Each ArrayController for its corresponding object simply implements controllerDidChangeContent() .

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

There is no comparison to find what it is for. :-)

0
source

Source: https://habr.com/ru/post/1269335/


All Articles