Как использовать undoManager с основным объектом данных
У меня есть NSManagedObject appointment
что я редактирую атрибуты. Если я нажимаю " Отмена", я хочу отменить все эти изменения.
Если я делаю (пример кода)
[[appointment managedObjectContext] setUndoManager:[[NSUndoManager alloc] init]]; //however doing a nslog on undoManager still shows it as (null);
[[[appointment managedObjectContext] undoManager] beginUndoGrouping];
appointment.startTime = 11;
appointment.endTime = 12;
appointment.customer = @"Tom";
[[[appointment managedObjectContext] undoManager] endUndoGrouping];
[[[appointment managedObjectContext] undoManager] undo];
не должно ли это отменить все изменения между ними beginUndoGrouping
а также endUndoGrouping
? Кажется, есть много способов сделать это, но я не могу найти правильный путь. Как правильно отменить изменения на NSManagedObject
?
2 ответа
Я полагаю, что это всего лишь пример порядка, в котором будут происходить события, а не фактический пример.
Вы случайно забыли дать ManagedObjectContext NSUndoManager?
Я полагаю, что вы получаете один по умолчанию под OS X, но под iOS, вы должны специально предоставить один.
Вы хотите быть уверены, что установите менеджер отмены при создании вашего MOC...
managedObjectContext.undoManager = [[NSUndoManager alloc] init];
Если undo-manager равен nil, после этого вы используете несколько MOC или какой-то другой код сбросил его.
Кроме того, в целях отладки проверьте свойство assign.managedObjectContext и убедитесь, что оно не равно nil и ссылается на действительный MOC.
РЕДАКТИРОВАТЬ
Хорошо, я просто пошел и написал быстрый тест, используя простую модель. Может быть, вы должны сделать что-то подобное, чтобы увидеть, где ваши утверждения терпят неудачу (вы можете просто добавить нормальное утверждение в путь к коду - я сделал это в качестве модульного теста, чтобы я мог легко добавить его в существующий проект).
- (void)testUndoManager
{
NSDate *now = [NSDate date];
NSManagedObjectContext *moc = [self managedObjectContextWithConcurrencyType:NSConfinementConcurrencyType];
STAssertNil(moc.undoManager, @"undoManager is nil by default in iOS");
moc.undoManager = [[NSUndoManager alloc] init];
[moc.undoManager beginUndoGrouping];
NSManagedObject *object = [NSEntityDescription insertNewObjectForEntityForName:EVENT_ENTITY_NAME inManagedObjectContext:moc];
STAssertNotNil(moc, @"Managed Object is nil");
STAssertEquals(moc, object.managedObjectContext, @"MOC of object should be same as MOC");
STAssertNotNil(object.managedObjectContext.undoManager, @"undoManager of MOC should not be nil");
[object setValue:now forKey:@"timestamp"];
STAssertEqualObjects(now, [object valueForKey:@"timestamp"], @"Timestamp should be NOW");
[moc.undoManager endUndoGrouping];
STAssertEqualObjects(now, [object valueForKey:@"timestamp"], @"Timestamp should be NOW");
[moc.undoManager undo];
STAssertNil([object valueForKey:@"timestamp"], @"Object access should be nil because changes were undone");
}
РЕДАКТИРОВАТЬ
MOC управляемого объекта может быть установлен равным нулю при нескольких условиях. Например, если вы удалите объект, а затем сохраните мод, MOC будет установлен равным nil для этого объекта...
NSManagedObject *object = [NSEntityDescription insertNewObjectForEntityForName:@"SomeEntity" inManagedObjectContext:moc];
[object.managedObjectContext deleteObject:object];
[moc save:0];
// object.managedObjectContext will be nil
Другой, менее распространенный случай, но признак того, что в MOC может быть проблема с памятью... В ARC MOC управляемого объекта является слабым указателем. Таким образом, если MOC исчезнет, этот указатель будет сброшен на ноль. В не-ARC указатель будет просто иметь старое значение, и ваши результаты будут неопределенными... возможно, сбой.
Таким образом, если значение управляемого объекта Object.managedObjectManager равно нулю, наиболее вероятными виновниками являются:
- Объект никогда не был вставлен в MOC
- Объект был удален из MOC
- МОК был удален
Основная причина, по которой отмена не работает с Core Data, заключается не в создании и настройке диспетчера отмены...
newManager = [[[NSUndoManager alloc] init] autorelease];
[newManager setLevelsOfUndo:4];
myManagedObjectContext.undoManager = newManager;
Вам также не нужна отмена начала / конца, так как это сделано для вас.
Также возможно (частично потому, что это сделано для вас), что отмена не будет работать, пока вы не вернетесь в цикл обработки событий и не будете вызваны в следующий раз. (Другими словами, удаление пользователем нажатия кнопки отмены может не работать.)
Ах, вы только что добавили комментарий выше. Пожалуйста, опубликуйте код, который выполняет настройку, так как ваш undo Manager, равный null, очевидно, сделает его неработающим.