I'm currently developing an app that uses Core Data. I'm using two stores/configurations, one for static content and one for user content. Occasionally on startup I get a crash saying "Can't add the same store twice". I haven't been able to track this down or regularly repeat it, so I'm wondering if anyone can shed any insight? Is this just a development bug that will go away upon release (unlikely, I know). Is there anything wrong that you can see with my code below for creating the persistent stores?
One other thing that may be worth mentioning is that I have all my Core Data access code wrapped up in a singleton class. I guess, it might be possible that two threads are accessing the managedObjectContext
very close together, resulting in near-simultaneous access to the persistentStoreCoordinator
?
Note:
sharedPaths
is an array of short path names, eg. @"Data_Static", @"Data_User"
sharedConfigurations
is an array of configuration names, eg. @"Static", @"User"
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator {
if (_persistentStoreCoordinator != nil) {
return _persistentStoreCoordinator;
}
NSString* documentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
NSFileManager* fileManager = [NSFileManager defaultManager];
NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption, [NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption, nil];
_persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel: [self managedObjectModel]];
//load each store/configuration
for(int i=0; i<[sharedPaths count]; i++) {
NSString* path = [sharedPaths objectAtIndex:i];
NSString* configuration = nil;
if([sharedConfigurations count] > 0) {
configuration = [sharedConfigurations objectAtIndex:i];
}
NSString* storePath = [d开发者_如何学CocumentsDirectory stringByAppendingPathComponent:[NSString stringWithFormat:@"%@.sqlite", path]];
//if the store doesn't exist, copy over the default store
if(![fileManager fileExistsAtPath:storePath]) {
NSString* defaultStorePath = [[NSBundle mainBundle] pathForResource:path ofType:@"sqlite"];
if(defaultStorePath) {
[fileManager copyItemAtPath:defaultStorePath toPath:storePath error:NULL];
}
}
NSURL* storeURL = [NSURL fileURLWithPath:storePath];
NSError* error = nil;
if(![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:configuration URL:storeURL options:options error:&error]) {
NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
exit(-1);
}
}
return _persistentStoreCoordinator;
}
If you think it's a threading problem, put it into a synchronized block :
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator {
@synchronized(self) {
if (_persistentStoreCoordinator != nil) {
return _persistentStoreCoordinator;
}
...
}
}
This will stop two threads running the code at the same time.
(You might need to add this pattern to any other methods that can't be run by different threads simultaneously.)
精彩评论