Отмена NSUndoManager Не работает С Core Data
-
21-09-2019 - |
Вопрос
Я пытаюсь создать приложение для 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 здесь.Надеюсь, это поможет.