问题
I have an app where I download the data on startup using a list of operations and it crashes randomly for unknown core data reasons so I spent few days on checking the best practices to update/fetch data in multithreading core data with MagicalRecord. One of the options was to enable the multithreading debugger -com.apple.CoreData.ConcurrencyDebug 1
where Xcode stops the apps when it violates one of their rules. So, Xcode stops my app on this line [SyncRequestEntity MR_createEntityInContext:[self getPrivateContext]]
+ (MagicalRecordVersionNumber) version
{
return MagicalRecordVersionNumber2_3;
}
@implementation NSManagedObjectContext (MagicalRecord)
+ (NSManagedObjectContext *) MR_context
{
return [self MR_contextWithParent:[self MR_rootSavingContext]];
}
+ (NSManagedObjectContext *) MR_contextWithParent:(NSManagedObjectContext *)parentContext
{
NSManagedObjectContext *context = [self MR_newPrivateQueueContext];
[context setParentContext:parentContext];
[context MR_obtainPermanentIDsBeforeSaving];
return context;
}
- (void) MR_obtainPermanentIDsBeforeSaving
{
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(MR_contextWillSave:)
name:NSManagedObjectContextWillSaveNotification
object:self];
}
+ (NSManagedObjectContext *) MR_newPrivateQueueContext
{
NSManagedObjectContext *context = [[self alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
MRLogInfo(@"Created new private queue context: %@", context);
return context;
}
@end
@implementation MyClass
- (NSManagedObjectContext *) getPrivateContext
{
if (self.privateContext == nil)
{
self.privateContext = [NSManagedObjectContext MR_context];
}
return self.privateContext;
}
- (SyncRequestEntity *) getSyncRequest
{
SyncRequestEntity *syncRequest = [SyncRequestEntity MR_findFirstByAttribute:@"key" withValue:self.itemKey inContext:[self getPrivateContext]];
// Checking if the entity was sync previously with the same filters.
if (syncRequest == nil)
{
syncRequest = [SyncRequestEntity MR_createEntityInContext: [self getPrivateContext]];
}
return syncRequest;
}
@end
@implementation NSManagedObject (MagicalRecord)
+ (id) MR_createEntityInContext:(NSManagedObjectContext *)context
{
if ([self respondsToSelector:@selector(insertInManagedObjectContext:)] && context != nil)
{
id entity = [self performSelector:@selector(insertInManagedObjectContext:) withObject:context];
return entity;
}
else
{
NSEntityDescription *entity = nil;
if (context == nil)
{
entity = [self MR_entityDescription];
}
else
{
entity = [self MR_entityDescriptionInContext:context];
}
if (entity == nil)
{
return nil;
}
return [[self alloc] initWithEntity:entity insertIntoManagedObjectContext:context];
}
}
@end
The privateContext
is a local variable for each operation so I have private contexts for each operation in order to not interrupt the main one. The point is that I create one private context for each thread and I'm just trying to create a new NSManagedObject
instance using this context and Xcode says that I'm violating the multithreading core data rules. Does anyone have any clue on what's happening?
回答1:
We have the same issue when developing our own app.
When you try to perform a write operation in a thread different to the context one, it crash sometimes.
Our solution was to make a private manager on the AppDelegate.m
file. Just add this code:
- (NSManagedObjectContext *)getPrivateManagedObjectContext
{
if (self.managedObjectContext != nil) {
return self.managedObjectContext;
}
NSPersistentStoreCoordinator *coordinator = [self getPersistentStoreCoordinator];
if (coordinator != nil) {
self.managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
[self.managedObjectContext setPersistentStoreCoordinator:coordinator];
}
return self.managedObjectContext;
}
Then when you need to perform any operation, you should use this method that ensures the block is running on the same thread of the context:
[self.managedObjectContext performBlock:^{...}];
[self.managedObjectContext performBlockAndWait:^{...}];
来源:https://stackoverflow.com/questions/32206967/multithreading-violation-core-data