1
\$\begingroup\$

I'm using Mulit-Context CoreData for Asynchronous Saving, which follows this architecture: enter image description here

Here is code stack:

class DatabaseInterface: NSObject {

static let shared = DatabaseInterface()
private var _mainThreadMOC: NSManagedObjectContext?
private var _masterMOC: NSManagedObjectContext?

func privateManagedObjectContext() -> NSManagedObjectContext {
    let privateMOC = NSManagedObjectContext(concurrencyType: .privateQueueConcurrencyType)
    privateMOC.parent = mainThreadManagedObjectContext()
    privateMOC.undoManager = nil
    return privateMOC
}
func mainThreadManagedObjectContext() -> NSManagedObjectContext {
    if _mainThreadMOC != nil {
        return _mainThreadMOC!
    }
    _mainThreadMOC = NSManagedObjectContext(concurrencyType: .mainQueueConcurrencyType)
    _mainThreadMOC!.parent = masterManagedObjectContext()
    _mainThreadMOC!.undoManager = nil
    return _mainThreadMOC!
}
private func masterManagedObjectContext() -> NSManagedObjectContext {
    if _masterMOC != nil {
        return _masterMOC!
    }
    _masterMOC = NSManagedObjectContext(concurrencyType: .privateQueueConcurrencyType)
    _masterMOC!.persistentStoreCoordinator = //persistant store coordinator
    _masterMOC!.undoManager = nil
    return _masterMOC!
}
}

Whenever I need to perform DB operations, e.g. non-UI related, I use privateMOC as:

let privateMOC = DatabaseInterface.shared.privateManagedObjectContext()
//do some DB operation
privateMOC.saveMOC()

And here is my MOC extension for saving:

extension NSManagedObjectContext {
func saveMOC() {
    //synchronous saving
    if self.saveMOCIfNeeded() {
        guard let parentMOC = self.parent else {
            return;
        }
        parentMOC.perform {
            //asynchronous saving
            if parentMOC.saveMOCIfNeeded() {
                guard let grandParentMOC = parentMOC.parent else {
                    return;
                }
                grandParentMOC.perform {
                    //asynchronous saving
                    grandParentMOC.saveMOCIfNeeded()
                }
            }
        }
    }
}
private func saveMOCIfNeeded() -> Bool {
    if !hasChanges {
        return false;
    }
    do {
        try self.save()
        return true
    }catch {
        print("\(error)")
        return false
    }
}
}

saveMOC() functions takes care of saving all the MOC hierarchy! It works with mainThreadMOC also as:

let mainThreadMOC = DatabaseInterface.shared.mainThreadManagedObjectContext()
//do some DB operation
mainThreadMOC.saveMOC()

I don't have to worry about which type of MOC I'm working on to save it.
Everything works fine!

My worries are:
1 Is there any scope to improve my code quality?
2 Will it affect performance as each-n-every saveMOC() call is saving changes to mainThreadMOC and 'masterMOC` also?

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.