From 51b615dd3971bce45e752981a1707cd315d8957e Mon Sep 17 00:00:00 2001 From: John Estropia Date: Sat, 18 Jul 2015 23:24:00 +0900 Subject: [PATCH] Updated Observing changes and notifications (markdown) --- Observing-changes-and-notifications.md | 110 ++++++++++++++----------- 1 file changed, 64 insertions(+), 46 deletions(-) diff --git a/Observing-changes-and-notifications.md b/Observing-changes-and-notifications.md index 7e9b80a..941599a 100644 --- a/Observing-changes-and-notifications.md +++ b/Observing-changes-and-notifications.md @@ -1,60 +1,78 @@ -To observe an object, implement the `ManagedObjectObserver` protocol and specify the `EntityType`: +CoreStore provides type-safe wrappers for observing managed objects: + +- `ObjectMonitor`: use to monitor changes to a single `NSManagedObject` instance (instead of Key-Value Observing) +- `ListMonitor`: use to monitor changes to a list of `NSManagedObject` instances (instead of `NSFetchedResultsController`) + +### Observe a single object + +To observe an object, implement the `ObjectObserver` protocol and specify the `EntityType`: ```swift -class MyViewController: UIViewController, ManagedObjectObserver { - func managedObjectWillUpdate(objectController: ManagedObjectController, object: MyPersonEntity) { +class MyViewController: UIViewController, ObjectObserver { + func objectMonitor(monitor: ObjectMonitor, willUpdateObject object: MyPersonEntity) { // ... } - func managedObjectWasUpdated(objectController: ManagedObjectController, object: MyPersonEntity, changedPersistentKeys: Set) { + func objectMonitor(monitor: ObjectMonitor, didUpdateObject object: MyPersonEntity, changedPersistentKeys: Set) { // ... } - func managedObjectWasDeleted(objectController: ManagedObjectController, object: MyPersonEntity) { + func objectMonitor(monitor: ObjectMonitor, didDeleteObject object: MyPersonEntity) { // ... } } ``` -We then need to keep a `ManagedObjectController` instance and register our `ManagedObjectObserver` as an observer: +We then need to keep a `ObjectMonitor` instance and register our `ObjectObserver` as an observer: ```swift let person: MyPersonEntity = // ... -self.objectController = CoreStore.observeObject(person) -self.objectController.addObserver(self) +self.monitor = CoreStore.monitorObject(person) +self.monitor.addObserver(self) ``` -The controller will then notify our observer whenever the object's attributes change. You can add multiple `ManagedObjectObserver`'s to a single `ManagedObjectController` without any problem. This means you can just share around the `ManagedObjectController` instance to different screens without problem. +The controller will then notify our observer whenever the object's attributes change. You can add multiple `ObjectObserver`s to a single `ObjectMonitor` without any problem. This means you can just share around the `ObjectMonitor` instance to different screens without problem. -You can get `ManagedObjectController`'s object through its `object` property. If the object is deleted, the `object` property will become `nil` to prevent further access. +You can get `ObjectMonitor`'s object through its `object` property. If the object is deleted, the `object` property will become `nil` to prevent further access. -While `ManagedObjectController` exposes `removeObserver(...)` as well, it only stores `weak` references of the observers and will safely unregister deallocated observers. +While `ObjectMonitor` exposes `removeObserver(...)` as well, it only stores `weak` references of the observers and will safely unregister deallocated observers. -#### Observe a list of objects -To observe a list of objects, implement one of the `ManagedObjectListChangeObserver` protocols and specify the `EntityType`: +### Observe a list of objects +To observe a list of objects, implement one of the `ListObserver` protocols and specify the `EntityType`: ```swift -class MyViewController: UIViewController, ManagedObjectListChangeObserver { - func managedObjectListWillChange(listController: ManagedObjectListController) { +class MyViewController: UIViewController, ListObserver { + func listMonitorWillChange(monitor: ListMonitor) { // ... } - func managedObjectListDidChange(listController: ManagedObjectListController) { + func listMonitorDidChange(monitor: ListMonitor) { // ... } } ``` -Including `ManagedObjectListChangeObserver`, there are 3 observer protocols you can implement depending on how detailed you need to handle a change notification: -- `ManagedObjectListChangeObserver`: lets you handle these callback methods: - - `func managedObjectListWillChange(listController: ManagedObjectListController)` - - `func managedObjectListDidChange(listController: ManagedObjectListController)` -- `ManagedObjectListObjectObserver`: in addition to `ManagedObjectListChangeObserver` methods, also lets you handle object inserts, updates, and deletes: - - `func managedObjectList(listController: ManagedObjectListController, didInsertObject object: T, toIndexPath indexPath: NSIndexPath)` - - `func managedObjectList(listController: ManagedObjectListController, didDeleteObject object: T, fromIndexPath indexPath: NSIndexPath)` - - `func managedObjectList(listController: ManagedObjectListController, didUpdateObject object: T, atIndexPath indexPath: NSIndexPath)` - - `func managedObjectList(listController: ManagedObjectListController, didMoveObject object: T, fromIndexPath: NSIndexPath, toIndexPath: NSIndexPath)` -- `ManagedObjectListSectionObserver`: in addition to `ManagedObjectListObjectObserver` methods, also lets you handle section inserts and deletes: - - `func managedObjectList(listController: ManagedObjectListController, didInsertSection sectionInfo: NSFetchedResultsSectionInfo, toSectionIndex sectionIndex: Int)` - - `func managedObjectList(listController: ManagedObjectListController, didDeleteSection sectionInfo: NSFetchedResultsSectionInfo, fromSectionIndex sectionIndex: Int)` - -We then need to create a `ManagedObjectListController` instance and register our `ManagedObjectListChangeObserver` as an observer: +Including `ListObserver`, there are 3 observer protocols you can implement depending on how detailed you need to handle a change notification: +- `ListObserver`: lets you handle these callback methods: ```swift -self.listController = CoreStore.observeObjectList( + func listMonitorWillChange(monitor: ListMonitor) + + func listMonitorDidChange(monitor: ListMonitor) +``` +- `ListObjectObserver`: in addition to `ListObserver` methods, also lets you handle object inserts, updates, and deletes: +```swift + func listMonitor(monitor: ListMonitor, didInsertObject object: MyPersonEntity, toIndexPath indexPath: NSIndexPath) + + func listMonitor(monitor: ListMonitor, didDeleteObject object: MyPersonEntity, fromIndexPath indexPath: NSIndexPath) + + func listMonitor(monitor: ListMonitor, didUpdateObject object: MyPersonEntity, atIndexPath indexPath: NSIndexPath) + + func listMonitor(monitor: ListMonitor, didMoveObject object: MyPersonEntity, fromIndexPath: NSIndexPath, toIndexPath: NSIndexPath) +``` +- `ListSectionObserver`: in addition to `ListObjectObserver` methods, also lets you handle section inserts and deletes: +```swift + func listMonitor(monitor: ListMonitor, didInsertSection sectionInfo: NSFetchedResultsSectionInfo, toSectionIndex sectionIndex: Int) + + func listMonitor(monitor: ListMonitor, didDeleteSection sectionInfo: NSFetchedResultsSectionInfo, fromSectionIndex sectionIndex: Int) +``` + +We then need to create a `ListMonitor` instance and register our `ListObserver` as an observer: +```swift +self.monitor = CoreStore.monitorList( From(MyPersonEntity), Where("age > 30"), OrderBy(.Ascending("name")), @@ -62,22 +80,22 @@ self.listController = CoreStore.observeObjectList( fetchRequest.fetchBatchSize = 20 } ) -self.listController.addObserver(self) +self.monitor.addObserver(self) ``` -Similar to `ManagedObjectController`, a `ManagedObjectListController` can also have multiple `ManagedObjectListChangeObserver`'s registered to a single `ManagedObjectListController`. +Similar to `ObjectMonitor`, a `ListMonitor` can also have multiple `ListObserver`s registered to a single `ListMonitor`. -If you have noticed, the `observeObjectList(...)` method accepts `Where`, `OrderBy`, and `Tweak` clauses exactly like a fetch. As the list maintained by `ManagedObjectListController` needs to have a deterministic order, at least the `From` and `OrderBy` clauses are required. +If you have noticed, the `monitorList(...)` method accepts `Where`, `OrderBy`, and `Tweak` clauses exactly like a fetch. As the list maintained by `ListMonitor` needs to have a deterministic order, at least the `From` and `OrderBy` clauses are required. -A `ManagedObjectListController` created from `observeObjectList(...)` will maintain a single-section list. You can therefore access its contents with just an index: +A `ListMonitor` created from `monitorList(...)` will maintain a single-section list. You can therefore access its contents with just an index: ```swift -let firstPerson = self.listController[0] +let firstPerson = self.monitor[0] ``` -If the list needs to be grouped into sections, create the `ManagedObjectListController` instance with the `observeSectionedList(...)` method and a `SectionedBy` clause: +If the list needs to be grouped into sections, create the `ListMonitor` instance with the `monitorSectionedList(...)` method and a `SectionBy` clause: ```swift -self.listController = CoreStore.observeSectionedList( +self.monitor = CoreStore.monitorSectionedList( From(MyPersonEntity), - SectionedBy("age"), + SectionBy("age"), Where("gender", isEqualTo: "M"), OrderBy(.Ascending("age"), .Ascending("name")), Tweak { (fetchRequest) -> Void in @@ -85,13 +103,13 @@ self.listController = CoreStore.observeSectionedList( } ) ``` -A list controller created this way will group the objects by the attribute key indicated by the `SectionedBy` clause. One more thing to remember is that the `OrderBy` clause should sort the list in such a way that the `SectionedBy` attribute would be sorted together (a requirement shared by `NSFetchedResultsController`.) +A list controller created this way will group the objects by the attribute key indicated by the `SectionBy` clause. One more thing to remember is that the `OrderBy` clause should sort the list in such a way that the `SectionBy` attribute would be sorted together (a requirement shared by `NSFetchedResultsController`.) -The `SectionedBy` clause can also be passed a closure to transform the section name into a displayable string: +The `SectionBy` clause can also be passed a closure to transform the section name into a displayable string: ```swift -self.listController = CoreStore.observeSectionedList( +self.monitor = CoreStore.monitorSectionedList( From(MyPersonEntity), - SectionedBy("age") { (sectionName) -> String? in + SectionBy("age") { (sectionName) -> String? in "\(sectionName) years old" }, OrderBy(.Ascending("age"), .Ascending("name")) @@ -100,7 +118,7 @@ self.listController = CoreStore.observeSectionedList( This is useful when implementing a `UITableViewDelegate`'s section header: ```swift func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String? { - let sectionInfo = self.listController.sectionInfoAtIndex(section) + let sectionInfo = self.monitor.sectionInfoAtIndex(section) // sectionInfo is an NSFetchedResultsSectionInfo instance return sectionInfo.name } @@ -109,8 +127,8 @@ func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> To access the objects of a sectioned list, use an `NSIndexPath` or a tuple: ```swift let indexPath = NSIndexPath(forRow: 2, inSection: 1) -let person1 = self.listController[indexPath] -let person2 = self.listController[1, 2] +let person1 = self.monitor[indexPath] +let person2 = self.monitor[1, 2] // person1 and person2 are the same object ```