CoreData 和 NSManagedObjectContext
Posted
技术标签:
【中文标题】CoreData 和 NSManagedObjectContext【英文标题】:CoreData and NSManagedObjectContext 【发布时间】:2012-10-17 18:23:10 【问题描述】:我有这个功能,可以将对象从“fallbackstore”移动到 iCloud 存储,fallbackstore 是当 iCloud 不可用时保存对象的存储。
底线,我需要将对象(及其关系)从一个上下文移动到另一个上下文。
但是我收到了这个错误:
* 由于未捕获的异常“NSInternalInconsistencyException”而终止应用程序,原因:“上下文已经有一个协调器;无法替代。 * 首先抛出调用栈:
开:
foodSuccess = [moc save:&localError];
有人知道我哪里出错了(以及为什么)?提前致谢!
- (BOOL)seedStore:(NSPersistentStore *)store withPersistentStoreAtURL:(NSURL *)seedStoreURL error:(NSError * __autoreleasing *)error
BOOL success = YES;
NSLog(@"%s", __func__);
BOOL foodSuccess = YES;
BOOL sportSuccess = YES;
BOOL dailySuccess = YES;
BOOL activitySuccess = YES;
BOOL reportSuccess = YES;
BOOL userSuccess = YES;
BOOL ingredientSuccess = YES;
NSUInteger batchSize = 5000;
NSError *localError = nil;
NSManagedObjectModel *model = [NSManagedObjectModel mergedModelFromBundles:nil];
NSPersistentStoreCoordinator *seedPSC = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:model];
NSDictionary *seedStoreOptions = @ NSReadOnlyPersistentStoreOption : [NSNumber numberWithBool:YES] ;
NSPersistentStore *seedStore = [seedPSC addPersistentStoreWithType:NSSQLiteStoreType
configuration:nil
URL:seedStoreURL
options:seedStoreOptions
error:&localError];
if (seedStore)
NSManagedObjectContext *seedMOC = [[NSManagedObjectContext alloc] init];
[seedMOC setPersistentStoreCoordinator:seedPSC];
// Food
NSFetchRequest *fr = [NSFetchRequest fetchRequestWithEntityName:@"Food"];
fr.relationshipKeyPathsForPrefetching = @[@"daily", @"ingredient", @"ingredients"];
[fr setFetchBatchSize:batchSize];
NSArray *foods = [seedMOC executeFetchRequest:fr error:&localError];
NSManagedObjectContext *moc = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
[moc setPersistentStoreCoordinator:_psc];
NSUInteger i = 1;
for (Food *f in foods)
[self addFood:f toStore:store withContext:moc];
if (0 == (i % batchSize))
foodSuccess = [moc save:&localError];
if (foodSuccess)
[moc reset];
else
NSLog(@"Error saving during seed (Food): %@", localError);
break;
i++;
if ([moc hasChanges])
foodSuccess = [moc save:&localError];
[moc reset];
// Sport
NSFetchRequest *fetchSports = [NSFetchRequest fetchRequestWithEntityName:@"Sport"];
fetchSports.relationshipKeyPathsForPrefetching = @[@"activity"];
fetchSports.fetchBatchSize = batchSize;
NSArray *sports = [seedMOC executeFetchRequest:fetchSports error:&localError];
NSManagedObjectContext *sportContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
sportContext.persistentStoreCoordinator = _psc;
NSUInteger iSports = 1;
for (Sport *s in sports)
[self addSport:s toStore:store withContext:sportContext];
if (0 == (iSports % batchSize))
sportSuccess = [moc save:&localError];
if (sportSuccess)
[moc reset];
else
NSLog(@"Error saving during seed (Sport): %@", localError);
break;
iSports++;
if ([sportContext hasChanges])
sportSuccess = [sportContext save:&localError];
[sportContext reset];
// Daily
NSFetchRequest *fetchDailies = [NSFetchRequest fetchRequestWithEntityName:@"Daily"];
fetchDailies.relationshipKeyPathsForPrefetching = @[@"food", @"user"];
fetchDailies.fetchBatchSize = batchSize;
NSArray *dailies = [seedMOC executeFetchRequest:fetchDailies error:&localError];
NSManagedObjectContext *dailiesContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
dailiesContext.persistentStoreCoordinator = _psc;
NSUInteger iDailies = 1;
for(Daily *d in dailies)
[self addDaily:d toStore:store withContext:dailiesContext];
if(0 == (iDailies % batchSize))
dailySuccess = [dailiesContext save:&localError];
if (dailySuccess)
[dailiesContext reset];
else
NSLog(@"Error saving during seed (Daily): %@", localError);
break;
iDailies++;
if ([dailiesContext hasChanges])
dailySuccess = [dailiesContext save:&localError];
[dailiesContext reset];
// Ingredient
NSFetchRequest *fetchIngredients = [NSFetchRequest fetchRequestWithEntityName:@"Ingredient"];
fetchIngredients.relationshipKeyPathsForPrefetching = @[@"food", @"foods"];
fetchIngredients.fetchBatchSize = batchSize;
NSArray *ingredients = [seedMOC executeFetchRequest:fetchIngredients error:&localError];
NSManagedObjectContext *ingredientsContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
ingredientsContext.persistentStoreCoordinator = _psc;
NSUInteger iIngredients = 1;
for(Ingredient *i in ingredients)
[self addIngredient:i toStore:store withContext:ingredientsContext];
if(0 == (iIngredients % batchSize))
ingredientSuccess = [ingredientsContext save:&localError];
if (ingredientSuccess)
[ingredientsContext reset];
else
NSLog(@"Error saving during seed (Ingredient): %@", localError);
break;
iIngredients++;
if ([ingredientsContext hasChanges])
ingredientSuccess = [ingredientsContext save:&localError];
[ingredientsContext reset];
// Activity
NSFetchRequest *fetchActivities = [NSFetchRequest fetchRequestWithEntityName:@"Activity"];
fetchActivities.relationshipKeyPathsForPrefetching = @[@"sport", @"user"];
fetchActivities.fetchBatchSize = batchSize;
NSArray *activities = [seedMOC executeFetchRequest:fetchActivities error:&localError];
NSManagedObjectContext *activitiesContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
dailiesContext.persistentStoreCoordinator = _psc;
NSUInteger iActivities = 1;
for(Activity *a in activities)
[self addActivity:a toStore:store withContext:activitiesContext];
if(0 == (iActivities % batchSize))
activitySuccess = [activitiesContext save:&localError];
if (activitySuccess)
[activitiesContext reset];
else
NSLog(@"Error saving during seed (Activity): %@", localError);
break;
iActivities++;
if ([activitiesContext hasChanges])
activitySuccess = [activitiesContext save:&localError];
[activitiesContext reset];
// Report
NSFetchRequest *fetchReports = [NSFetchRequest fetchRequestWithEntityName:@"Report"];
fetchReports.relationshipKeyPathsForPrefetching = @[@"user"];
fetchReports.fetchBatchSize = batchSize;
NSArray *reports = [seedMOC executeFetchRequest:fetchReports error:&localError];
NSManagedObjectContext *reportsContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
reportsContext.persistentStoreCoordinator = _psc;
NSUInteger iReports = 1;
for(Report *r in reports)
[self addReport:r toStore:store withContext:reportsContext];
if(0 == (iReports % batchSize))
reportSuccess = [reportsContext save:&localError];
if (reportSuccess)
[reportsContext reset];
else
NSLog(@"Error saving during seed (Report): %@", localError);
break;
iReports++;
if ([reportsContext hasChanges])
reportSuccess = [reportsContext save:&localError];
[reportsContext reset];
// User
NSFetchRequest *fetchUsers = [NSFetchRequest fetchRequestWithEntityName:@"User"];
fetchUsers.relationshipKeyPathsForPrefetching = @[@"activities", @"dailies", @"reports"];
fetchUsers.fetchBatchSize = batchSize;
NSArray *users = [seedMOC executeFetchRequest:fetchUsers error:&localError];
NSManagedObjectContext *usersContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
usersContext.persistentStoreCoordinator = _psc;
NSUInteger iUsers = 1;
for(User *u in users)
[self addUser:u toStore:store withContext:usersContext];
if(0 == (iUsers % batchSize))
userSuccess = [usersContext save:&localError];
if (userSuccess)
[usersContext reset];
else
NSLog(@"Error saving during seed (User): %@", localError);
break;
iUsers++;
if ([usersContext hasChanges])
userSuccess = [usersContext save:&localError];
[usersContext reset];
// Result
success = foodSuccess && sportSuccess && dailySuccess && ingredientSuccess && activitySuccess && reportSuccess && userSuccess;
else
success = NO;
NSLog(@"Error adding seed store: %@", localError);
if (NO == success)
if (localError && (error != NULL))
*error = localError;
return success;
- (void)addFood:(Food *)food toStore:(NSPersistentStore *)store withContext:(NSManagedObjectContext *)moc
NSEntityDescription *entity = [food entity];
Food *newFood = [[Food alloc] initWithEntity:entity insertIntoManagedObjectContext:moc];
newFood.alcol = food.alcol;
newFood.amid = food.amid;
newFood.bookmark = food.bookmark;
newFood.calcium = food.calcium;
newFood.cho = food.cho;
newFood.cholesterol = food.cholesterol;
newFood.complex = food.complex;
newFood.copper = food.copper;
newFood.dirty = food.dirty;
newFood.edible = food.edible;
newFood.fat = food.fat;
newFood.fatMono = food.fatMono;
newFood.fatPoli = food.fatPoli;
newFood.fatSat = food.fatSat;
newFood.fibre = food.fibre;
newFood.iron = food.iron;
newFood.kcal = food.kcal;
newFood.lookback = food.lookback;
newFood.magnesium = food.magnesium;
newFood.name = food.name;
newFood.note = food.note;
newFood.phosphorus = food.phosphorus;
newFood.potassium = food.potassium;
newFood.pro = food.pro;
newFood.recipe = food.recipe;
newFood.recordUUID = (food.recordUUID == nil) ? [[[NSUUID alloc] init] UUIDString] : food.recordUUID;
newFood.serving = food.serving;
newFood.servingDesc = food.servingDesc;
newFood.sodium = food.sodium;
newFood.userAdd = food.userAdd;
newFood.vitA = food.vitA;
newFood.vitC = food.vitC;
newFood.vitE = food.vitE;
newFood.water = food.water;
newFood.zinc = food.zinc;
newFood.dosePeople = food.dosePeople;
newFood.daily = food.daily;
for(Ingredient *i in food.ingredients)
NSEntityDescription *entityIngredient = [i entity];
Ingredient *newIngredient = [[Ingredient alloc] initWithEntity:entityIngredient insertIntoManagedObjectContext:moc];
[newFood addIngredientsObject:newIngredient];
NSMutableSet *ing = [food mutableSetValueForKey:@"ingredient"];
for(Ingredient *i in ing)
NSLog(@"%s Name: %@", __func__, i.food.name);
NSEntityDescription *entityIngredient = [i entity];
Ingredient *newIngredient = [[Ingredient alloc] initWithEntity:entityIngredient insertIntoManagedObjectContext:moc];
[newFood addIngredientsObject:newIngredient];
[moc assignObject:newFood toPersistentStore:store];
【问题讨论】:
【参考方案1】:这可能是也可能不是您遇到错误的原因,但如果您使用 NSPrivateQueueConcurrencyType
初始化 MOC,您应该严格通过 -performBlock:
和 -performBlockAndWait:
访问它。看到这个相关的question。
【讨论】:
以上是关于CoreData 和 NSManagedObjectContext的主要内容,如果未能解决你的问题,请参考以下文章
iOS - 使用 CoreData 的 dispatch_async 保留周期