OSDN Git Service

saveメソッドを一本化
[kcd/KCD.git] / KCD / CoreDataManager.swift
index 788e1f3..b97c131 100644 (file)
@@ -30,13 +30,15 @@ protocol CoreDataProvider {
     
     var context: NSManagedObjectContext { get }
     
-    func save(errorHandler: (Error) -> Void)
-    func save() throws
-    func removeDataFile()
+    func save(errorHandler: @escaping (Error) -> Void)
 }
 
 protocol CoreDataAccessor: CoreDataProvider {
     
+    func sync(execute: () -> Void)
+    func sync<T>(execute: () -> T) -> T
+    func async(execute: @escaping () -> Void)
+    
     func insertNewObject<T>(for entity: Entity<T>) -> T?
     func delete(_ object: NSManagedObject)
     func object<T>(of entity: Entity<T>, with objectId: NSManagedObjectID) -> T?
@@ -47,11 +49,24 @@ protocol CoreDataAccessor: CoreDataProvider {
 
 protocol CoreDataManager: CoreDataAccessor {
     
-    associatedtype InstanceType = Self
+    static var `default`: Self { get }
     
-    static var `default`: InstanceType { get }
+    static func oneTimeEditor() -> Self
+}
+
+func presentOnMainThread(_ error: Error) {
     
-    static func oneTimeEditor() -> InstanceType
+    if Thread.isMainThread {
+        
+        NSApp.presentError(error)
+        
+    } else {
+        
+        DispatchQueue.main.sync {
+            
+            _ = NSApp.presentError(error)
+        }
+    }
 }
 
 // MARK: - Extension
@@ -60,85 +75,81 @@ extension CoreDataProvider {
     static func context(for type: CoreDataManagerType) -> NSManagedObjectContext {
         
         switch type {
-        case .reader: return core.parentContext
+        case .reader: return core.readerContext
             
         case .editor: return core.editorContext()
         }
     }
     
-    func save(errorHandler: (Error) -> Void) {
+    func save(errorHandler: @escaping (Error) -> Void = presentOnMainThread) {
         
-        do {
-            
-            try save()
+        // parentを辿ってsaveしていく
+        func propagateSaveAsync(_ context: NSManagedObjectContext) {
             
-        } catch {
-            
-            errorHandler(error)
-        }
-    }
-    
-    func save() throws {
-        
-        guard context.commitEditing() else {
+            guard let parent = context.parent else {
+                
+                return
+            }
             
-            throw CoreDataError.couldNotSave("\(String(describing: type(of: self))) unable to commit editing before saveing")
+            parent.perform {
+                
+                do {
+                    
+                    try parent.save()
+                    
+                    propagateSaveAsync(parent)
+                    
+                } catch {
+                    
+                    errorHandler(error)
+                }
+            }
         }
         
-        do {
+        context.performAndWait {
             
-            try context.save()
-            
-        } catch (let error as NSError) {
-            
-            throw CoreDataError.couldNotSave(error.localizedDescription)
-        }
-        
-        guard let parent = context.parent else { return }
-        
-        // save parent context
-        var catchedError: NSError? = nil
-        parent.performAndWait {
+            guard context.commitEditing() else {
+                
+                errorHandler(CoreDataError.couldNotSave("Unable to commit editing before saveing"))
+                return
+            }
             
             do {
                 
-                try parent.save()
+                try context.save()
+                
+                // save reader and writer context async.
+                // non throw exceptions.
+                propagateSaveAsync(context)
                 
-            } catch (let error as NSError) {
+            } catch let error as NSError {
                 
-                catchedError = error
+                errorHandler(CoreDataError.couldNotSave(error.localizedDescription))
             }
         }
-        
-        if let error = catchedError {
-            
-            throw CoreDataError.couldNotSave(error.localizedDescription)
-            
-        }
     }
+}
+
+extension CoreDataAccessor {
     
-    func removeDataFile() {
+    func sync(execute work: () -> Void) {
         
-        MOCGenerator(type(of: self).core.config).removeDataFile()
+        self.context.performAndWait(work)
     }
     
-    func presentOnMainThread(_ error: Error) {
+    func sync<T>(execute work: () -> T) -> T {
         
-        if Thread.isMainThread {
-            
-            NSApp.presentError(error)
-            
-        } else {
-            
-            DispatchQueue.main.sync {
-                
-                _ = NSApp.presentError(error)
-            }
+        var value: T!
+        sync {
+            value = work()
         }
+        return value
+    }
+    
+    func async(execute work: @escaping () -> Void) {
+        
+        self.context.perform(work)
     }
-}
-
-extension CoreDataAccessor {
     
     func insertNewObject<T>(for entity: Entity<T>) -> T? {
         
@@ -161,11 +172,39 @@ extension CoreDataAccessor {
         req.sortDescriptors = sortDescriptors
         req.predicate = predicate
         
-        return try context.fetch(req)
+        var result: [T]?
+        var caughtError: Error?
+        sync {
+            do {
+                
+                result = try self.context.fetch(req)
+            } catch {
+                
+                caughtError = error
+            }
+        }
+        if let error = caughtError {
+            
+            throw error
+        }
+        
+        return result ?? []
     }
     
     func object(with objectId: NSManagedObjectID) -> NSManagedObject {
         
-        return context.object(with: objectId)
+        var result: NSManagedObject?
+        sync {
+            result = self.context.object(with: objectId)
+        }
+        return result!
+    }
+}
+
+extension CoreDataManager {
+    
+    static func oneTimeEditor() -> Self {
+        
+        return Self.init(type: .editor)
     }
 }