I have CoreDataStack
I've added debug options for CoreData debugging "-com.apple.CoreData.ConcurrencyDebug 1"
class CoreDataStack {
public enum SaveStatus {
    case saved, rolledBack, hasNoChanges, error
}
private var modelName: String
var viewContext: NSManagedObjectContext
var privateContext: NSManagedObjectContext
var persisterContainer: NSPersistentContainer
init(_ modelName: String) {
    self.modelName = modelName
    let container = NSPersistentContainer(name: modelName)
    container.loadPersistentStores { persisterStoreDescription, error in
        print("CoreData", "Initiated \(persisterStoreDescription)")
        guard error == nil else {
            print("CoreData", "Unresolved error \(error!)")
            return
        }
    }
    self.persisterContainer = container
    self.viewContext = container.viewContext
    self.viewContext.automaticallyMergesChangesFromParent = true
    self.privateContext = NSManagedObjectContext(concurrencyType: .privateQueueConcurrencyType)
    self.privateContext.persistentStoreCoordinator = container.persistentStoreCoordinator
    self.privateContext.automaticallyMergesChangesFromParent = true
}
func createTemporaryViewContext() -> NSManagedObjectContext {
    let context = NSManagedObjectContext(concurrencyType: .mainQueueConcurrencyType)
    context.parent = self.privateContext
    context.automaticallyMergesChangesFromParent = true
    return context
}
func saveTempViewContext(tempContext context: NSManagedObjectContext, completion: ((CoreDataStack.SaveStatus) -> Void)? = nil) {
    guard context.hasChanges || privateContext.hasChanges else {
        completion?(.hasNoChanges)
        return
    }
    context.performAndWait {
        do {
            try context.save()
        }
        catch {
            completion?(.error)
            return
        }
    }
    privateContext.perform { [weak self] in
        do {
            try self?.privateContext.save()
            completion?(.saved)
        }
        catch {
            self?.privateContext.rollback()
            completion?(.rolledBack)
        }
    }
}
class ViewController: UIViewController {
@objc
func save(_ sender: UIBarButtonItem) {
    let coreDataStack = CoreDataStack()
    let tempMainContext = coreDataStack.createTemporaryViewContext() //child main context from private context
    var people = People(context: tempMainContext)
    self.people.name = "John Doe"
    self.people.age = 25
    coreDataStack.saveTempViewContext(tempContext: tempMainContext) { status in
        print(status)
    }
}
}
I have "privateContext" attached to coordinator
I've created "tempMainContext" from private context
When I call "saveTempViewContext" I want to save tempMainContext which pushes changes to parent (privateContext) and this privateContext saves to persistent store
So the error occurred in line
privateContext.hasChanges
I know thats this line executes in main thread. And I need to call method "perform" or "performAndWait" to perform on the right queue.
like this
    var contextHasChanges: Bool = false
    var privateContextHasChanges: Bool = false
    context.performAndWait {
        contextHasChanges = context.hasChanges
    }
    privateContext.performAndWait {
        privateContextHasChanges = privateContext.hasChanges
    }
    guard context.hasChanges || privateContext.hasChanges else {
        completion?(.hasNoChanges)
        return
    }
But it so weird to call "performAndWait" just to check that context has changes. And when I call "performAndWait" it block current thread in my case it MainThread. And I don't want block the main thread even for short time.
How could we resolve this issue ?
UPD 2
In my CoreDataStack init method in below I'v added code. I just check if the private context has changes and It will crash
let privateContextHasChanges = privateContext.hasChanges
I think it's because at that line we are in MainThread and we touch private context which init with "privateQueueConcurrencyType" and I investigate that if I touch other property for example "privateContext.name" or "privateContext.parent" it works fine.
But if I touch property like this:
privateContext.hasChanges
privateContext.registeredObjects
privateContext.updatedObjects
maybe other
it will crash again
So I can make a conclusion that these properties are not thread safe.
Can anyone confirm that ?
UPD 3 After I'v read post Unexpected Core Data Multithreading Violation
I'v made conclusions:
- If I'm on the main thread and my context's type is .main I do not need any changes and I safe
 - If I'm on some place and I don't know want kind of thread I'm on I always need to do "perform" or "performAndWait" to synchonize queue attached to context.
 - Almost always do "perform" and not "performAndWait" except you can't do without it.
 
