mirror of
https://github.com/JohnEstropia/CoreStore.git
synced 2026-01-18 15:07:00 +01:00
Updated Observing changes and notifications (markdown)
@@ -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<MyPersonEntity>, object: MyPersonEntity) {
|
||||
class MyViewController: UIViewController, ObjectObserver {
|
||||
func objectMonitor(monitor: ObjectMonitor<MyPersonEntity>, willUpdateObject object: MyPersonEntity) {
|
||||
// ...
|
||||
}
|
||||
|
||||
func managedObjectWasUpdated(objectController: ManagedObjectController<MyPersonEntity>, object: MyPersonEntity, changedPersistentKeys: Set<KeyPath>) {
|
||||
func objectMonitor(monitor: ObjectMonitor<MyPersonEntity>, didUpdateObject object: MyPersonEntity, changedPersistentKeys: Set<KeyPath>) {
|
||||
// ...
|
||||
}
|
||||
|
||||
func managedObjectWasDeleted(objectController: ManagedObjectController<MyPersonEntity>, object: MyPersonEntity) {
|
||||
func objectMonitor(monitor: ObjectMonitor<MyPersonEntity>, 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<MyPersonEntity>) {
|
||||
class MyViewController: UIViewController, ListObserver {
|
||||
func listMonitorWillChange(monitor: ListMonitor<MyPersonEntity>) {
|
||||
// ...
|
||||
}
|
||||
|
||||
func managedObjectListDidChange(listController: ManagedObjectListController<MyPersonEntity>) {
|
||||
func listMonitorDidChange(monitor: ListMonitor<MyPersonEntity>) {
|
||||
// ...
|
||||
}
|
||||
}
|
||||
```
|
||||
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<T>)`
|
||||
- `func managedObjectListDidChange(listController: ManagedObjectListController<T>)`
|
||||
- `ManagedObjectListObjectObserver`: in addition to `ManagedObjectListChangeObserver` methods, also lets you handle object inserts, updates, and deletes:
|
||||
- `func managedObjectList(listController: ManagedObjectListController<T>, didInsertObject object: T, toIndexPath indexPath: NSIndexPath)`
|
||||
- `func managedObjectList(listController: ManagedObjectListController<T>, didDeleteObject object: T, fromIndexPath indexPath: NSIndexPath)`
|
||||
- `func managedObjectList(listController: ManagedObjectListController<T>, didUpdateObject object: T, atIndexPath indexPath: NSIndexPath)`
|
||||
- `func managedObjectList(listController: ManagedObjectListController<T>, 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<T>, didInsertSection sectionInfo: NSFetchedResultsSectionInfo, toSectionIndex sectionIndex: Int)`
|
||||
- `func managedObjectList(listController: ManagedObjectListController<T>, 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<MyPersonEntity>)
|
||||
|
||||
func listMonitorDidChange(monitor: ListMonitor<MyPersonEntity>)
|
||||
```
|
||||
- `ListObjectObserver`: in addition to `ListObserver` methods, also lets you handle object inserts, updates, and deletes:
|
||||
```swift
|
||||
func listMonitor(monitor: ListMonitor<MyPersonEntity>, didInsertObject object: MyPersonEntity, toIndexPath indexPath: NSIndexPath)
|
||||
|
||||
func listMonitor(monitor: ListMonitor<MyPersonEntity>, didDeleteObject object: MyPersonEntity, fromIndexPath indexPath: NSIndexPath)
|
||||
|
||||
func listMonitor(monitor: ListMonitor<MyPersonEntity>, didUpdateObject object: MyPersonEntity, atIndexPath indexPath: NSIndexPath)
|
||||
|
||||
func listMonitor(monitor: ListMonitor<MyPersonEntity>, 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<MyPersonEntity>, didInsertSection sectionInfo: NSFetchedResultsSectionInfo, toSectionIndex sectionIndex: Int)
|
||||
|
||||
func listMonitor(monitor: ListMonitor<MyPersonEntity>, 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
|
||||
```
|
||||
|
||||
|
||||
Reference in New Issue
Block a user