Core Data & GCD: Passing the correct managed object context to custom NSManagedObjects

只谈情不闲聊 提交于 2019-12-03 03:58:31

That error generally relates to using a managed object incorrectly context across different threads or queues. You created the MOC on the main queue, but you're using it on a background queue without considering that fact. It's not wrong to use the MOC on a background queue, but you need to be aware of that and take preparations.

You didn't say how you're creating the MOC. I suggest that you should be doing this:

NSManagedObjectContext *context = [[NSManagedObjectContext alloc]
    initWithConcurrencyType: NSMainQueueConcurrencyType];

With main queue concurrency you can just use it normally on the main thread. When you're in your dispatch queue though, do this:

[context performBlockAndWait:^{
    NSFetchRequest *request = [NSFetchRequest 
        fetchRequestWithEntityName:NSStringFromClass([self class])];
    NSPredicate *predicate = 
       [NSPredicate predicateWithFormat:@"coa == %@",coaStr];
    request.predicate = predicate;
    NSArray *results = [context executeFetchRequest:request error:nil];
    // ...
}];

This will ensure that the MOC's work occurs on the main thread even though you're on a background queue. (Technically what it actually means is that the MOC's work in the background will be correctly synchronized with work it does on the main queue, but the result is the same: this is the safe way to do this).

A similar approach would be to use NSPrivateQueueConcurrencyType instead. If you do that, you'd use performBlock or performBlockAndWait everywhere for the MOC, not just on background threads.

First,

"how to pass the correct managed object context down to my custom NSManagedObjects."

We create NSManagedObject with NSManagedObjectContext. not the other way around. So, when you have a NSManagedObject, you can access the NSManagedObjectContext by asking its property: – managedObjectContext as listed in Apple Document

Second,

When working with CoreData, multi-threading could be a little tricky. especially for the beginner. The are all kind of details that you need to take care of.

I highly recommend you checkout the Parent-Child NSManagedContext. then, using MagicRecord.

By using MagicRecord, you can simply Grand Central Dispatch with a Block like this:

[MagicalRecord saveInBackgroundWithBlock:^(NSManagedObjectContext *localContext){

    // here use the `localContext` as your NSManagedContext and do things in the background.
    // it will take care of all the rest.

}];

If you need to pass NSManagedObject into this block, remember to only pass the NSManagedObjectID instead of the proprety.

this is a example.

NSManagedObjectID *coaMapID = CoaMap.objectID;

[MagicalRecord saveInBackgroundWithBlock:^(NSManagedObjectContext *localContext){
    coaMap *aCoaMap = (coaMap *)[localContext existingObjectWithID:coaMapID error:&error];
    // then use aCoaMap normally.
}];

Hope this helped.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!