我想这只是事件进行顺序的一个例子,而不是一个实际的例子。
您是否偶然忘记给 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 消失,该指针将被重置为零。在非 ARC 下,指针将只有旧值,您的结果将是未定义的……可能是崩溃。
因此,如果 managedObject.managedObjectManager 为 nil,则最可能的罪魁祸首是:
- 该对象从未插入 MOC
- 该对象已从 MOC 中删除
- MOC 已删除