-
Notifications
You must be signed in to change notification settings - Fork 68
/
NSManagedObjectContext+Rx.swift
128 lines (107 loc) · 6.18 KB
/
NSManagedObjectContext+Rx.swift
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
import Foundation
import CoreData
import RxSwift
public extension Reactive where Base: NSManagedObjectContext {
/**
Executes a fetch request and returns the fetched objects as an `Observable` array of `NSManagedObjects`.
- parameter fetchRequest: an instance of `NSFetchRequest` to describe the search criteria used to retrieve data from a persistent store
- parameter sectionNameKeyPath: the key path on the fetched objects used to determine the section they belong to; defaults to `nil`
- parameter cacheName: the name of the file used to cache section information; defaults to `nil`
- returns: An `Observable` array of `NSManagedObjects` objects that can be bound to a table view.
*/
func entities<T: NSManagedObject>(fetchRequest: NSFetchRequest<T>,
sectionNameKeyPath: String? = nil,
cacheName: String? = nil) -> Observable<[T]> {
return Observable.create { observer in
let observerAdapter = FetchedResultsControllerEntityObserver(observer: observer, fetchRequest: fetchRequest, managedObjectContext: self.base, sectionNameKeyPath: sectionNameKeyPath, cacheName: cacheName)
return Disposables.create {
observerAdapter.dispose()
}
}
}
/**
Executes a fetch request and returns the fetched section objects as an `Observable` array of `NSFetchedResultsSectionInfo`.
- parameter fetchRequest: an instance of `NSFetchRequest` to describe the search criteria used to retrieve data from a persistent store
- parameter sectionNameKeyPath: the key path on the fetched objects used to determine the section they belong to; defaults to `nil`
- parameter cacheName: the name of the file used to cache section information; defaults to `nil`
- returns: An `Observable` array of `NSFetchedResultsSectionInfo` objects that can be bound to a table view.
*/
func sections<T: NSManagedObject>(fetchRequest: NSFetchRequest<T>,
sectionNameKeyPath: String? = nil,
cacheName: String? = nil) -> Observable<[NSFetchedResultsSectionInfo]> {
return Observable.create { observer in
let frc = NSFetchedResultsController(fetchRequest: fetchRequest,
managedObjectContext: self.base,
sectionNameKeyPath: sectionNameKeyPath,
cacheName: cacheName)
let observerAdapter = FetchedResultsControllerSectionObserver(observer: observer, frc: frc)
return Disposables.create {
observerAdapter.dispose()
}
}
}
/**
Performs transactional update, initiated on a separate managed object context, and propagating thrown errors.
- parameter updateAction: a throwing update action
*/
func performUpdate(updateAction: (NSManagedObjectContext) throws -> Void) throws {
let privateContext = NSManagedObjectContext(concurrencyType: .privateQueueConcurrencyType)
privateContext.parent = self.base
try updateAction(privateContext)
guard privateContext.hasChanges else { return }
try privateContext.save()
try self.base.save()
}
}
public extension Reactive where Base: NSManagedObjectContext {
/**
Creates, inserts, and returns a new `NSManagedObject` instance for the given `Persistable` concrete type (defaults to `Persistable`).
*/
private func create<E: Persistable>(_ type: E.Type = E.self) -> E.T {
return NSEntityDescription.insertNewObject(forEntityName: E.entityName, into: self.base) as! E.T
}
private func get<P: Persistable>(_ persistable: P) throws -> P.T? {
let fetchRequest: NSFetchRequest<P.T> = NSFetchRequest(entityName: P.entityName)
fetchRequest.predicate = persistable.predicate()
let result = (try self.base.execute(fetchRequest)) as! NSAsynchronousFetchResult<P.T>
return result.finalResult?.first
}
/**
Attempts to retrieve remove a `Persistable` object from a persistent store, and then attempts to commit that change or throws an error if unsuccessful.
- seealso: `Persistable`
- parameter persistable: a `Persistable` object
*/
func delete<P: Persistable>(_ persistable: P) throws {
if let entity = try get(persistable) {
self.base.delete(entity)
do {
try entity.managedObjectContext?.save()
} catch let e {
print(e)
}
}
}
/**
Creates and executes a fetch request and returns the fetched objects as an `Observable` array of `Persistable`.
- parameter type: the `Persistable` concrete type; defaults to `Persistable`
- parameter format: the format string for the predicate; defaults to `""`
- parameter arguments: the arguments to substitute into `format`, in the order provided; defaults to `nil`
- parameter sortDescriptors: the sort descriptors for the fetch request; defaults to `nil`
- returns: An `Observable` array of `Persistable` objects that can be bound to a table view.
*/
func entities<P: Persistable>(_ type: P.Type = P.self,
predicate: NSPredicate? = nil,
sortDescriptors: [NSSortDescriptor]? = nil) -> Observable<[P]> {
let fetchRequest: NSFetchRequest<P.T> = NSFetchRequest(entityName: P.entityName)
fetchRequest.predicate = predicate
fetchRequest.sortDescriptors = sortDescriptors ?? [NSSortDescriptor(key: P.primaryAttributeName, ascending: true)]
return entities(fetchRequest: fetchRequest).map {$0.map(P.init)}
}
/**
Attempts to fetch and update (or create if not found) a `Persistable` instance. Will throw error if fetch fails.
- parameter persistable: a `Persistable` instance
*/
func update<P: Persistable>(_ persistable: P) throws {
persistable.update(try get(persistable) ?? self.create(P.self))
}
}