Why am I getting a CoreData threading violation when I try to access a property of the selected object?

The following code works without the last statement. However, with the last line, Xcode stops and displays the following message:

CoreData` + [NSManagedObjectContext Multithreading_Violation_AllThatIsLeftToUsIsHonor ]

 NSManagedObjectContext *context = GLOBAL_appDelegate.coreDataHelper.contextBackground;
    [context performBlock:^{
         NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
         [fetchRequest setEntity:[NSEntityDescription entityForName:@"CdTag" inManagedObjectContext:context]];
         NSPredicate *predicate = [NSPredicate predicateWithFormat:@"title BEGINSWITH[cd] %@", @"webpages"];
         [fetchRequest setPredicate:predicate];
         NSArray *cdTags = [context executeFetchRequest:fetchRequest error:nil];
         NSLog(@"number of tags: %li", cdTags.count);
         CdTag *cdTag = [cdTags objectAtIndex:0];

         // Accessing a property causes the assertion warning to be shown
         cdTag.title;
    }];

      

I am using Xcode 7 beta 5 and I have multithreading assertions.

The contexts are defined as follows:

_model = [NSManagedObjectModel mergedModelFromBundles:nil];
_coordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:_model];
_context = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
[_context setPersistentStoreCoordinator:_coordinator];

_contextBackground = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
[_contextBackground setParentContext:_context];

      

Is this an Xcode bug or am I doing something wrong?

+3


source to share


2 answers


The problem occurs when building for iOS 9.0.



+1


source


Could you also add some code where the context initialization happens?

The error received is related to accessing the managed entity context from a thread / queue other than the one in which it was initialized.

What usually happens is that the managed entity context is initialized using the default / deprecated concurrency type "constraint type" for which

performBlock: 

      

and

performBlockAndWait:

      

the methods won't actually do what they advertise. ie make sure the context is available on the queue it was associated with during initialization.

If what I suggested above is what actually happens, you can (assuming everything else is in place) fix it by initializing your context like this:



_managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];

      

or

_managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];

      

Here's the docs in the concurrency strategy:

When you create a managed object context using initWithConcurrencyType: you have three options for its thread (queue) association

Confinement (NSConfinementConcurrencyType)

This is the default for backward compatibility. You promise that this context will not be used by any thread other than the one on which you created it. In general, to make the behavior explicit, you are encouraged to use one of the other types.

This type of concurrency can only be used if the parent storage of the management object context is the persistent storage coordinator.

Private Queue (NSPrivateQueueConcurrencyType)

The context creates and manages a private queue.

Main Queue (NSMainQueueConcurrencyType)

The context is associated with the main queue and as such is associated with the application event loop, but otherwise it is similar to a private queue-based context. This queue type is used for contexts related to controllers and UI objects that should only be used on the main thread.

If you use contexts using the constraint pattern, you send context messages directly; so that you send messages from the correct queue.

You are using contexts using queue-based concurrency types in combination with performBlock: and performBlockAndWait :.

Apple Docs

As a side note, the error message you receive is one of the last few Easter eggs still sitting inside Cocoa.

+2


source







All Articles