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 保留周期

删除时如何手动管理Core Data关系

@dynamic 使用的常见情况是啥?

如何列出 NSManagedObject 的变量

CoreData父、母子关系,一个CoreData子类可以和两个子类有相同的关系吗?

CoreData 和 NSComboBox