2 // CoreDataManager.swift
5 // Created by Hori,Masaki on 2017/10/26.
6 // Copyright © 2017年 Hori,Masaki. All rights reserved.
11 enum CoreDataManagerType {
17 enum CoreDataError: Error {
19 case saveLocationIsUnuseable
20 case couldNotCreateModel
21 case couldNotCreateCoordinator(String)
22 case couldNotSave(String)
25 protocol CoreDataProvider {
27 init(type: CoreDataManagerType)
29 static var core: CoreDataCore { get }
31 var context: NSManagedObjectContext { get }
33 func save(errorHandler: @escaping (Error) -> Void)
36 protocol CoreDataAccessor: CoreDataProvider {
38 func sync(execute: () -> Void)
39 func sync<T>(execute: () -> T) -> T
40 func async(execute: @escaping () -> Void)
42 func insertNewObject<T>(for entity: Entity<T>) -> T?
43 func delete(_ object: NSManagedObject)
44 func object<T>(of entity: Entity<T>, with objectId: NSManagedObjectID) -> T?
45 func objects<T>(of entity: Entity<T>, sortDescriptors: [NSSortDescriptor]?, predicate: NSPredicate?) throws -> [T]
47 func object(with objectId: NSManagedObjectID) -> NSManagedObject
50 protocol CoreDataManager: CoreDataAccessor {
52 static var `default`: Self { get }
54 static func oneTimeEditor() -> Self
57 func presentOnMainThread(_ error: Error) {
59 if Thread.isMainThread {
61 NSApp.presentError(error)
65 DispatchQueue.main.sync {
67 _ = NSApp.presentError(error)
73 extension CoreDataProvider {
75 static func context(for type: CoreDataManagerType) -> NSManagedObjectContext {
78 case .reader: return core.readerContext
80 case .editor: return core.editorContext()
84 func save(errorHandler: @escaping (Error) -> Void = presentOnMainThread) {
87 func propagateSaveAsync(_ context: NSManagedObjectContext) {
89 guard let parent = context.parent else {
100 propagateSaveAsync(parent)
109 context.performAndWait {
111 guard context.commitEditing() else {
113 errorHandler(CoreDataError.couldNotSave("Unable to commit editing before saveing"))
121 // save reader and writer context async.
122 // non throw exceptions.
123 propagateSaveAsync(context)
125 } catch let error as NSError {
127 errorHandler(CoreDataError.couldNotSave(error.localizedDescription))
133 extension CoreDataAccessor {
135 func sync(execute work: () -> Void) {
137 self.context.performAndWait(work)
140 func sync<T>(execute work: () -> T) -> T {
149 func async(execute work: @escaping () -> Void) {
151 self.context.perform(work)
154 func insertNewObject<T>(for entity: Entity<T>) -> T? {
156 return NSEntityDescription.insertNewObject(forEntityName: entity.name, into: context) as? T
159 func delete(_ object: NSManagedObject) {
161 context.delete(object)
164 func object<T>(of entity: Entity<T>, with objectId: NSManagedObjectID) -> T? {
166 return context.object(with: objectId) as? T
169 func objects<T>(of entity: Entity<T>, sortDescriptors: [NSSortDescriptor]? = nil, predicate: NSPredicate? = nil) throws -> [T] {
171 let req = NSFetchRequest<T>(entityName: entity.name)
172 req.sortDescriptors = sortDescriptors
173 req.predicate = predicate
176 var caughtError: Error?
180 result = try self.context.fetch(req)
186 if let error = caughtError {
194 func object(with objectId: NSManagedObjectID) -> NSManagedObject {
196 var result: NSManagedObject?
198 result = self.context.object(with: objectId)
204 extension CoreDataManager {
206 static func oneTimeEditor() -> Self {
208 return Self.init(type: .editor)