我有一个名为appointment
的NSManagedObject,我编辑了它的属性。如果我用户按取消,我想撤消所有这些编辑。
如果我这样做(示例代码)
[[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
上的更改的正确方法是什么?
答案 0 :(得分:7)
我想这只是事件发生顺序的一个例子,而不是一个实际的例子。
你偶然忘了给ManagedObjectContext一个NSUndoManager吗?
我相信你在OS X下默认获得一个,但在iOS下,你必须专门提供一个。
您希望确保在创建MOC时设置撤消管理器...
managedObjectContext.undoManager = [[NSUndoManager alloc] init];
如果undo-manager为nil,那么在执行此操作后,您将使用多个MOC,或者其他一些代码已重置它。
此外,出于调试目的,请检查appointment.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可以设置为nil。例如,如果删除一个对象,然后保存该mod,那么该对象的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消失,该指针将被重置为nil。在非ARC下,指针将只有旧值,结果将是未定义的...可能是崩溃。
因此,如果managedObject.managedObjectManager为零,则最可能的罪魁祸首是:
答案 1 :(得分:0)
撤消无法使用Core Data的最大原因是没有创建和设置撤消管理器...
newManager = [[[NSUndoManager alloc] init] autorelease];
[newManager setLevelsOfUndo:4];
myManagedObjectContext.undoManager = newManager;
您也不需要开始/结束undoGrouping,就像为您完成的那样。
也可能(部分原因是为你完成),在你回到事件循环并下次调用之前,撤消将无法工作。 (换句话说,切断用户按下撤消按钮可能无效。)
啊,你刚刚添加了上面的评论。请发布执行该设置的代码,因为undoManager为null显然会使其无效。