Just thinking about this, and having looked at some of the other solutions I think there might be a simpler solution?
I’m working on the premise that the notification.userInfo will provide the arrays of Locations that we need to process. Therefore there is no need to go back to CoreData and query for these - proving the first efficiency saving.
Therefore within the notification closure we should be able to extract two arrays of Location - one for deleted, one for added + updated, and then, via the selector, pass these on to a function to update the display selectively, rather than just calling updatedLocations.
There is a bit of extra fun, as despite the note in the book, the dictionary item is a set not an array.
A bit like:
var managedObjectContext: NSManagedObjectContext! {
didSet {
NotificationCenter.default.addObserver(forName: Notification.Name.NSManagedObjectContextObjectsDidChange,
object: managedObjectContext,
queue: OperationQueue.main) {notification in
if self.isViewLoaded {
var updated = [Location]()
var removed = [Location]()
if let dictionary = notification.userInfo {
if let set = dictionary["inserted"] as? Set<Location> {
updated = Array(set)
}
if let set = dictionary["deleted"] as? Set<Location>{
removed = Array(set)
}
if let set = dictionary["updated"] as? Set<Location>{
updated.append(contentsOf: Array(set))
}
self.refreshLocations(deleted: removed, udopated: updated)
}
}
}
}
}
}
func refreshLocations(deleted deletedLocations:[Location], udpated updatedLocations: [Location]) {
let allLocations = deletedLocations + updatedLocations
mapView.removeAnnotations(allLocations)
mapView.addAnnotations(updatedlocations)
}
If this works, and base on some quick testing it seems to, it would probably be worth refactoring upateLocations() to call refreshLocations(deleted: update: ) passing in its locations array for both parameters. The would remove duplication of code.