问题
I have a very simple Core Data demo, in which there is only one button.
When I click the 'run' button, the App creates 10,000 objects in a for-loop, which is running in the global queue.
Update for more detail : If I put the for-loop in main thread, it runs well.
Update for my intent : I know that MOC is not thread-safe, but according to the Apple doc, we can also use serial queue to access the MOC, and the serial queue uses more than one threads.
Here I create the Core Data stack:
#pragma mark - Core Data Stack
- (NSManagedObjectContext *)managedObjectContext
{
if (nil != _managedObjectContext) {
return _managedObjectContext;
}
_managedObjectContext = [[NSManagedObjectContext alloc] init];
if (self.persistentStoreCoordinator) {
[_managedObjectContext setPersistentStoreCoordinator:self.persistentStoreCoordinator];
}
return _managedObjectContext;
}
- (NSManagedObjectModel *)managedObjectModel
{
if (nil != _managedObjectModel) {
return _managedObjectModel;
}
_managedObjectModel = [NSManagedObjectModel mergedModelFromBundles:nil];
return _managedObjectModel;
}
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator
{
if (nil != _persistentStoreCoordinator) {
return _persistentStoreCoordinator;
}
NSString *storeType = NSSQLiteStoreType;
NSString *storeName = @"model.sqlite";
NSURL *storeURL = [NSURL fileURLWithPath:[[self applicationDocumentsDirectory] stringByAppendingPathComponent:storeName]];
_persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:self.managedObjectModel];
NSError *error = nil;
if (![_persistentStoreCoordinator addPersistentStoreWithType:storeType
configuration:nil
URL:storeURL
options:nil
error:&error])
{
NSLog(@"Error : %@\n", [error localizedDescription]);
NSAssert1(YES, @"Failed to create store %@ with NSSQLiteStoreType", [storeURL path]);
}
return _persistentStoreCoordinator;
}
#pragma mark -
#pragma mark Application's Documents Directory
- (NSString *)applicationDocumentsDirectory
{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *basePath = ([paths count] > 0) ? [paths objectAtIndex:0] : nil;
return basePath;
}
after app has launched :
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// Override point for customization after application launch.
if (self.managedObjectContext) {
;
}
return YES;
}
When I click the button :
- (IBAction)runButtonDidClick:(id)sender
{
/**
* Access the moc using different threads to make deadlock.
*/
[self runSave];
}
- (void)runSave
{
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
AppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
NSManagedObjectContext *moc = appDelegate.managedObjectContext;
if (moc) {
for (int j = 0; j < 10000; ++j) {
People *people = [NSEntityDescription insertNewObjectForEntityForName:@"People" inManagedObjectContext:moc];
people.name = @"noname";
}
NSLog(@"**********IN SAVE %@", [NSThread currentThread]);
NSError *error = nil;
if ([moc save:&error]) {
;
}
NSLog(@"**********OUT SAVE %@", [NSThread currentThread]);
}
});
}
For clicking the run button some times, maybe 2 or 3 or 4... It crashes
I could not figure out why... Thanks for any help.


回答1:
Core data should be always work on thread witch have moc.
the only job for performBlock
and performBlockAndWait
is that take care of thread safety. With it inserting to Core Data will always running in the right thread. You can define moc on whatever thread you want - performBlock
always choose the right one.
So:
[self.managedObjectContext performBlock:^{
for(NSDictionary *dic in arr) {
//inserting here!
}
}];
In your case:
- (void)runSave
{
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
AppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
NSManagedObjectContext *moc = appDelegate.managedObjectContext;
if (moc) {
[moc performBlock:^{
for (int j = 0; j < 10000; ++j) {
People *people = [NSEntityDescription insertNewObjectForEntityForName:@"People" inManagedObjectContext:moc];
people.name = @"noname";
}
NSError *error = nil;
if ([moc save:&error]) {
;
}
}];
}
});
}
来源:https://stackoverflow.com/questions/16958662/core-data-inserting-objects-crashed-in-global-queue-arc-iphone-simulator-6