CoreData и mergeChangesFromContextDidSaveNotification

Я создаю addManagedObjectContext в качестве области блокнота для новых сущностей, а затем объединяю новую сущность с моим основным ManagedObjectContext в «Сохранить», как показано в примере CoreDataBooks.

После слияния новой сущности как получить краткую ссылку на нее для использования при отображении подробного представления?

Вы должны заставить контроллер результатов выборки выйти и снова выполнить выборку (дорого, как указано в коде CoreDataBooks)? Я предполагаю, что начальный идентификатор объекта в «addManagedObjectContext» не останется прежним после его слияния.

В проекте Recipes эта проблема не возникает, потому что вы создаете новую сущность и работаете с ней в одном ManagedObjectContext. Следовательно, у вас есть ссылка на вновь созданный элемент, чтобы показать его подробное представление.

Из CoreDataBooks:

/**
 Add controller's delegate method; informs the delegate that the add operation has completed, and indicates 
 whether the user saved the new book.
 */
- (void)addViewController:(AddViewController *)controller didFinishWithSave:(BOOL)save {

    if (save) {
        /*
         The new book is associated with the add controller's managed object context.
         This is good because it means that any edits that are made don't affect the 
         application's main managed object context -- it's a way of keeping disjoint edits 
         in a separate scratchpad -- but it does make it more difficult to get the new book 
         registered with the fetched results controller.

         First, you have to save the new book.  This means it will be added to the persistent 
         store.  Then you can retrieve a corresponding managed object into the application 
         delegate's context.  Normally you might do this using a fetch or using objectWithID: -- for example

         NSManagedObjectID *newBookID = [controller.book objectID];
         NSManagedObject *newBook = [applicationContext objectWithID:newBookID];

         These techniques, though, won't update the fetch results controller, which 
         only observes change notifications in its context.

         You don't want to tell the fetch result controller to perform its fetch again 
         because this is an expensive operation.

         You can, though, update the main context using mergeChangesFromContextDidSaveNotification: which 
         will emit change notifications that the fetch results controller will observe.
         To do this:
         1  Register as an observer of the add controller's change notifications
         2  Perform the save
         3  In the notification method (addControllerContextDidSave:), merge the changes
         4  Unregister as an observer
         */
        NSNotificationCenter *dnc = [NSNotificationCenter defaultCenter];
        [dnc addObserver:self selector:@selector(addControllerContextDidSave:) name:NSManagedObjectContextDidSaveNotification object:addingManagedObjectContext];

        NSError *error;
        if (![addingManagedObjectContext save:&error]) {
            // Update to handle the error appropriately.
            NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
            exit(-1);  // Fail
        }
        [dnc removeObserver:self name:NSManagedObjectContextDidSaveNotification object:addingManagedObjectContext];
    }
    // Release the adding managed object context.
    self.addingManagedObjectContext = nil;

    // Dismiss the modal view to return to the main list
    [self dismissModalViewControllerAnimated:YES];
}


/**
 Notification from the add controller's context's save operation. This is used to update the 
 fetched results controller's managed object context with the new book instead of performing 
 a fetch (which would be a much more computationally expensive operation).
 */
- (void)addControllerContextDidSave:(NSNotification*)saveNotification {

    NSLog(@"addControllerContextDidSave");
    NSManagedObjectContext *context = [fetchedResultsController managedObjectContext];
    // Merging changes causes the fetched results controller to update its results
    [context mergeChangesFromContextDidSaveNotification:saveNotification];  
}

person Alexi Groove    schedule 15.09.2009    source источник


Ответы (1)


Глядя на эти комментарии, похоже, что они говорят о контроллерах полученных результатов. Поэтому было бы довольно дорого заставить FRC выполнить новую выборку после того, как вы только что изменили один объект, поэтому вы можете объединить свой контекст добавления с ним, чтобы уведомить его о любых изменениях.

После того, как вы выполнили сохранение и слияние, любые управляемые объекты, на которые у вас есть ссылка в контексте добавления, больше не будут иметь идентификаторов временных объектов, поскольку они существуют в постоянном хранилище. Поэтому вы можете запомнить идентификаторы и использовать [applicationContext objectWithID: newBookID] в контексте основного приложения, чтобы получить дескриптор объекта, который вы ищете. Это вернет объект (со всеми его изменениями) в контексте приложения.

После слияния вполне вероятно, что объект существует в памяти и никакого похода в магазин не требуется. Однако даже если это так, поскольку вы имеете дело только с одним объектом для отображения в подробном представлении, это вообще не проблема. Переход в магазин вместо контекстной памяти происходит медленнее, но, очевидно, должен происходить много раз во время вашего приложения, и это вряд ли вызовет проблемы, если вы не имеете дело с МНОГО данных!

Надеюсь это поможет!

person Michael Waterfall    schedule 16.09.2009
comment
Итак, вы говорите, что если я сохраню идентификатор объекта 'newBook', когда он все еще находится в addManagedObjectContext (сразу после вызова [addManagedObjectContext save: & error] ', я могу ссылаться на него и использовать его после завершения слияния ? - person Alexi Groove; 16.09.2009
comment
Да, вы сможете использовать этот objectID в любых других контекстах, которые у вас есть, и, если вы объединили изменения из контекста добавления, у вас будет самый последний объект. - person Michael Waterfall; 17.09.2009