enum CoreDataError: Error {
- case applicationDirectoryIsFile
+ case saveLocationIsUnuseable
case couldNotCreateModel
case couldNotCreateCoordinator(String)
+ case couldNotSave(String)
}
protocol CoreDataProvider {
var context: NSManagedObjectContext { get }
- func save()
+ func save(errorHandler: (Error) -> Void)
+ func save() throws
func removeDataFile()
}
// MARK: - Extension
extension CoreDataProvider {
- func save() {
+ static func context(for type: CoreDataManagerType) -> NSManagedObjectContext {
+
+ switch type {
+ case .reader: return core.parentContext
+
+ case .editor: return core.editorContext()
+ }
+ }
+
+ func save(errorHandler: (Error) -> Void) {
- if !context.commitEditing() {
+ do {
+
+ try save()
- print("\(String(describing: type(of: self))) unable to commit editing before saveing")
+ } catch {
- return
+ errorHandler(error)
+ }
+ }
+
+ func save() throws {
+
+ guard context.commitEditing() else {
+
+ throw CoreDataError.couldNotSave("\(String(describing: type(of: self))) unable to commit editing before saveing")
}
do {
try context.save()
- } catch {
+ } catch (let error as NSError) {
- presentOnMainThread(error)
+ throw CoreDataError.couldNotSave(error.localizedDescription)
}
- if let p = context.parent {
+ guard let parent = context.parent else { return }
+
+ // save parent context
+ var catchedError: NSError? = nil
+ parent.performAndWait {
- p.performAndWait {
- do {
-
- try p.save()
-
- } catch {
-
- self.presentOnMainThread(error)
- }
+ do {
+
+ try parent.save()
+
+ } catch (let error as NSError) {
+
+ catchedError = error
}
}
+
+ if let error = catchedError {
+
+ throw CoreDataError.couldNotSave(error.localizedDescription)
+
+ }
}
func removeDataFile() {
- removeAllDataFile(named: type(of: self).core.config.fileName)
+ MOCGenerator.removeDataFile(type(of: self).core.config)
}
- private func presentOnMainThread(_ error: Error) {
+ func presentOnMainThread(_ error: Error) {
if Thread.isMainThread {
}
}
}
-
- static func context(for type: CoreDataManagerType) -> NSManagedObjectContext {
-
- switch type {
- case .reader: return core.parentContext
-
- case .editor: return core.editorContext()
- }
- }
}
extension CoreDataAccessor {
import Cocoa
-func genarate(_ config: CoreDataConfiguration) throws -> (model: NSManagedObjectModel, coordinator: NSPersistentStoreCoordinator, moc: NSManagedObjectContext) {
+final class MOCGenerator {
- let model = try createModel(config)
- let coordinator = try getCoordinator(config, model)
- let moc = createContext(coordinator)
+ let config: CoreDataConfiguration
- return (model: model, coordinator: coordinator, moc: moc)
-}
-
-func removeAllDataFile(named name: String) {
-
- ["", "-wal", "-shm"]
- .map { name + $0 }
- .map(ApplicationDirecrories.support.appendingPathComponent)
- .forEach(removeDataFile)
-}
-
-private func removeDataFile(at url: URL) {
+ init(_ config: CoreDataConfiguration) {
+
+ self.config = config
+ }
- do {
+ func genarate() throws -> (model: NSManagedObjectModel, coordinator: NSPersistentStoreCoordinator, moc: NSManagedObjectContext) {
- try FileManager.default.removeItem(at: url)
+ let model = try createModel()
+ let coordinator = try createCoordinator(model)
+ let moc = createContext(coordinator)
- } catch {
+ return (model: model, coordinator: coordinator, moc: moc)
+ }
+
+ static func removeDataFile(_ config: CoreDataConfiguration) {
- print("Could not remove file for URL (\(url))")
+ ["", "-wal", "-shm"]
+ .map { config.fileName + $0 }
+ .map(ApplicationDirecrories.support.appendingPathComponent)
+ .forEach(removeFile)
}
-}
-
-// MARK: - NSManagedObjectContext and ...
-private func createModel(_ config: CoreDataConfiguration) throws -> NSManagedObjectModel {
- guard let modelURL = Bundle.main.url(forResource: config.modelName, withExtension: "momd"),
- let model = NSManagedObjectModel(contentsOf: modelURL) else {
+ private static func removeFile(at url: URL) {
+
+ do {
+
+ try FileManager.default.removeItem(at: url)
- throw CoreDataError.couldNotCreateModel
+ } catch {
+
+ print("Could not remove file for URL (\(url))")
+ }
}
- return model
-}
-
-private func getCoordinator(_ config: CoreDataConfiguration, _ model: NSManagedObjectModel) throws -> NSPersistentStoreCoordinator {
-
- do {
+ // MARK: - NSManagedObjectContext and ...
+ private func createModel() throws -> NSManagedObjectModel {
+
+ guard let modelURL = Bundle.main.url(forResource: config.modelName, withExtension: "momd"),
+ let model = NSManagedObjectModel(contentsOf: modelURL) else {
+
+ throw CoreDataError.couldNotCreateModel
+ }
- return try createCoordinator(config, model)
+ return model
+ }
+
+ private func createCoordinator(_ model: NSManagedObjectModel) throws -> NSPersistentStoreCoordinator {
- } catch (let error as NSError) {
+ if !checkDirectory(ApplicationDirecrories.support) {
+
+ throw CoreDataError.saveLocationIsUnuseable
+ }
- // Data Modelが更新されていたらストアファイルを削除してもう一度
- if error.domain == NSCocoaErrorDomain,
- (error.code == 134130 || error.code == 134110),
- config.tryRemake {
+ do {
- removeAllDataFile(named: config.fileName)
+ return try makeCoordinator(model)
- do {
-
- return try createCoordinator(config, model)
+ } catch (let error as NSError) {
+
+ // Data Modelが更新されていたらストアファイルを削除してもう一度
+ if error.domain == NSCocoaErrorDomain,
+ (error.code == 134130 || error.code == 134110),
+ config.tryRemake {
- } catch {
+ MOCGenerator.removeDataFile(config)
- print("Fail to create NSPersistentStoreCoordinator twice.")
+ do {
+
+ return try makeCoordinator(model)
+
+ } catch {
+
+ print("Fail to create NSPersistentStoreCoordinator twice.")
+ }
}
+
+ throw CoreDataError.couldNotCreateCoordinator(error.localizedDescription)
}
-
- throw error
}
-}
-
-private func createCoordinator(_ config: CoreDataConfiguration, _ model: NSManagedObjectModel) throws -> NSPersistentStoreCoordinator {
- if !checkDirectory(ApplicationDirecrories.support) {
+ private func makeCoordinator(_ model: NSManagedObjectModel) throws -> NSPersistentStoreCoordinator {
- let failureReason = "Can not use directory \(ApplicationDirecrories.support.path)"
+ let coordinator: NSPersistentStoreCoordinator = NSPersistentStoreCoordinator(managedObjectModel: model)
+ let url = ApplicationDirecrories.support.appendingPathComponent(config.fileName)
+ try coordinator.addPersistentStore(ofType: config.type,
+ configurationName: nil,
+ at: url,
+ options: config.options)
- throw CoreDataError.couldNotCreateCoordinator(failureReason)
+ return coordinator
}
- let coordinator: NSPersistentStoreCoordinator = NSPersistentStoreCoordinator(managedObjectModel: model)
- let url = ApplicationDirecrories.support.appendingPathComponent(config.fileName)
-
- try coordinator.addPersistentStore(ofType: config.type,
- configurationName: nil,
- at: url,
- options: config.options)
-
- return coordinator
-}
-
-private func createContext(_ coordinator: NSPersistentStoreCoordinator) -> NSManagedObjectContext {
-
- let moc = NSManagedObjectContext(concurrencyType: .mainQueueConcurrencyType)
- moc.persistentStoreCoordinator = coordinator
- moc.undoManager = nil
-
- return moc
+ private func createContext(_ coordinator: NSPersistentStoreCoordinator) -> NSManagedObjectContext {
+
+ let moc = NSManagedObjectContext(concurrencyType: .mainQueueConcurrencyType)
+ moc.persistentStoreCoordinator = coordinator
+ moc.undoManager = nil
+
+ return moc
+ }
}