Вопрос

Я пытаюсь создать приложение для iPhone, в котором пользователь может добавлять записи.Когда он нажимает на новую запись, всплывает окно с запросом на получение некоторой информации.Затем он может либо нажать "Отмена", либо "Сохранить", чтобы удалить данные или сохранить их на диск.

Для экономии я использую Core Data framework, который работает довольно хорошо.Однако я не могу заставить кнопку "Отмена" работать.Когда появляется окно с запросом информации, я создаю новый объект в контексте управляемого объекта (MOC).Затем, когда пользователь нажимает "Отмена", я пытаюсь использовать NSUndoManager, принадлежащий MOC.

Я также хотел бы сделать это, используя вложенные группы отмены, потому что там могут быть вложенные группы.

Чтобы проверить это, я написал простое приложение.Приложение представляет собой всего лишь шаблон "Оконного приложения" с включенными основными данными.Для базовой модели данных я создаю единую сущность под названием "Entity" с целочисленным атрибутом "x".Затем внутри applicationDidFinishLaunching я добавляю этот код:

- (void)applicationDidFinishLaunching:(UIApplication *)application {    

  // Override point for customization after app launch    

  unsigned int x=arc4random()%1000;
  [self.managedObjectContext processPendingChanges];
  [self.managedObjectContext.undoManager beginUndoGrouping];

  NSManagedObject *entity=[NSEntityDescription insertNewObjectForEntityForName:@"Entity" 
                                                        inManagedObjectContext:self.managedObjectContext];
  [entity setValue:[NSNumber numberWithInt:x] forKey:@"x"];
  NSLog(@"Insert Value %d",x);

  [self.managedObjectContext processPendingChanges];
  [self.managedObjectContext.undoManager endUndoGrouping];
  [self.managedObjectContext.undoManager undoNestedGroup];

  NSFetchRequest *fetchRequest=[[NSFetchRequest alloc] init];
  NSEntityDescription *entityEntity=[NSEntityDescription entityForName:@"Entity"
                                                inManagedObjectContext:self.managedObjectContext];
  [fetchRequest setEntity:entityEntity];
  NSArray *result=[self.managedObjectContext executeFetchRequest:fetchRequest error:nil];
  for(entity in result) {
    NSLog(@"FETCHED ENTITY %d",[[entity valueForKey:@"x"] intValue]);
  }

    [window makeKeyAndVisible];
}

Идея проста.Попробуйте вставить новый объект Entity, отменить его, извлечь все объекты Entity из MOC и распечатать их.Если все работало правильно, то в конце не должно быть никаких объектов.

Тем не менее, я получаю этот результат:

[Session started at 2010-02-20 13:41:49 -0800.]
2010-02-20 13:41:51.695 Untitledundotes[7373:20b] Insert Value 136
2010-02-20 13:41:51.715 Untitledundotes[7373:20b] FETCHED ENTITY 136

Как вы можете видеть, объект присутствует в MOC после того, как я пытаюсь отменить его создание.Есть какие-нибудь предложения относительно того, что я делаю не так?

Это было полезно?

Решение

Ваша проблема вызвана тем фактом, что, в отличие от OS X, контекст управляемого объекта iPhone по умолчанию не содержит менеджера отмены.Вам нужно явно добавить один из них.

Измените сгенерированный код в делегате приложения для свойства managedObjectContext, чтобы он выглядел следующим образом:

- (NSManagedObjectContext *) managedObjectContext {

    if (managedObjectContext != nil) {
        return managedObjectContext;
    }

    NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
    if (coordinator != nil) {
        managedObjectContext = [[NSManagedObjectContext alloc] init];
        //add the following 3 lines of code
        NSUndoManager *undoManager = [[NSUndoManager alloc] init];
        [managedObjectContext setUndoManager:undoManager];
        [undoManager release];
        [managedObjectContext setPersistentStoreCoordinator: coordinator];
    }

    return managedObjectContext;

}

После внесения этого изменения 2-е сообщение журнала больше не печатается.

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

Дэйв

Другие советы

Я попробовал подход Дейва, но у меня ничего не получилось.Я, наконец, нашел решение в примере Apple Основные базы данных

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

Вот моя адаптированная версия, где я использую статический объект для временного контекста для создания нового объекта ChannelMO.

//Gets a new ChannelMO that is part of the addingManagedContext
+(ChannelMO*) getNewChannelMO{

    // Create a new managed object context for the new channel -- set its persistent store coordinator to the same as that from the fetched results controller's context.
    NSManagedObjectContext *addingContext = [[NSManagedObjectContext alloc] init];
    addingManagedObjectContext = addingContext;

    [addingManagedObjectContext setPersistentStoreCoordinator:[[self getContext] persistentStoreCoordinator]];

    ChannelMO* aux = (ChannelMO *)[NSEntityDescription insertNewObjectForEntityForName:@"ChannelMO" inManagedObjectContext:addingManagedObjectContext];
    return aux;
}

+(void) saveAddingContext{
    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.
    addingManagedObjectContext = nil;
}

Я надеюсь, что это поможет

Гонсо

Это должно сработать.Правильно ли вы назначили диспетчер отмены вашему managedObjectContext?Если вы правильно это сделали, по умолчанию включена функция отмены регистрации, и все должно быть готово.Есть хорошая статья о core data здесь.Существует хороший учебник по core data и NSUndoManager здесь.Надеюсь, это поможет.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top