我在使用复杂模型时遇到NSUndoManager无法撤消的问题。
这是我的模特。
我有一个Singleton来处理核心数据,这是它的初始化:
model =[NSManagedObjectModel mergedModelFromBundles:nil];
NSPersistentStoreCoordinator *psc = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:model];
NSString *path = pathInDocumentDirectory(@"store.data");
NSURL *storeURL = [NSURL fileURLWithPath:path];
NSError *error = nil;
if(![psc addPersistentStoreWithType:NSSQLiteStoreType
configuration:nil
URL:storeURL
options:nil
error:&error]) {
[NSException raise:@"Open failed" format:@"Reason: %@", [error localizedDescription]];
}
context = [[NSManagedObjectContext alloc] init];
NSUndoManager *contextUndoManager = [[NSUndoManager alloc] init];
[contextUndoManager setLevelsOfUndo:20];
[context setUndoManager:contextUndoManager];
[context setPersistentStoreCoordinator:psc];
对于每个实体,我都有一个调用[self initWithEntity ...]的init方法,然后进入一些属性。这是HalfEdge实体的一个示例:
- (id) initWithVertex:(Vertex*) vert inManagedObjectContext: context {
NSEntityDescription* tEntityDescription = [NSEntityDescription entityForName: @"HalfEdge"
inManagedObjectContext: context];
self = [self initWithEntity: tEntityDescription insertIntoManagedObjectContext: context];
if(self) {
self.lastVertex = vert;
[self.lastVertex addHalfEdgeObject:self];
}
return self;
}
当用户添加新图形时,我创建一个新的图形实体,然后让用户添加点击屏幕的点。对于每个点,将执行可以添加和/或移除三角形实体,半边形和顶点的rutine。这是电话:
[[[DrawingsStore sharedStore].managedObjectContext undoManager] beginUndoGrouping];
[delaunay addPoint:CGPointMake(localizacion.x-dummy.bounds.size.width/2, localizacion.y-dummy.bounds.size.height/2)];
[[DrawingsStore sharedStore].managedObjectContext processPendingChanges];
[[[DrawingsStore sharedStore].managedObjectContext undoManager] endUndoGrouping];
正如您所看到的,我为该rutine中发生的所有事情设置了撤消组。
然后当按下按钮时我正在调用[[context undoManager] undo];但它什么也没做。
我在撤消之前和之后打印一个提取,它是相同的。我可以看到rutine工作正常,将所有正确的实体添加到核心数据中,但它根本不会撤消任何内容。
使用Aderstedt的消息进行编辑
好的,我删除了NSManagedObject子类的自定义init方法,并创建了一个类方法:
+ (HalfEdge*) addWithVertex:(Vertex*) vert inManagedObjectContext: context {
HalfEdge* halfEdge = [NSEntityDescription insertNewObjectForEntityForName:@"HalfEdge" inManagedObjectContext:context];
if(halfEdge) {
halfEdge.lastVertex = vert;
[halfEdge.lastVertex addHalfEdgeObject:self];
}
return halfEdge;
}
结果仍然相同。对象被创建,撤消不起作用。 (canUndo返回1)
修改
哇,我刚刚注册了undoManager的NSUndoManagerCheckpointNotification,一旦我点击撤消它就像循环一样永远张贴。好的,现在我知道我必须在某处做错事,但......在哪里?
答案 0 :(得分:2)
好的,我发现了。事实证明我在寻找错误的地方。
尝试调试NSUndoManager我注册了通知,发现NSUndoManagerCheckpointNotification一次又一次地被调用。
[delaunay addPoint ...]对模型进行所有更改。但同时运行渲染例程会将三角形渲染到屏幕上。在那个例程中,我设置了这些三角形的颜色。我需要在那里做,因为在渲染屏幕背景之前,我不知道应该放置的颜色。
对NSManagedObject子类Triangle的color属性的这些更改导致NSUndoManagerCheckpointNotification被触发并且撤消不起作用。如果我删除它,撤消工作。
所以我想我只需添加它,因此渲染期间所做的更改不会进入撤消堆栈。
[[[DibujosStore sharedStore] managedObjectContext] processPendingChanges];
[[[[DibujosStore sharedStore] managedObjectContext] undoManager] disableUndoRegistration];
[renderer render];
[[[DibujosStore sharedStore] managedObjectContext] processPendingChanges];
[[[[DibujosStore sharedStore] managedObjectContext] undoManager] enableUndoRegistration];
答案 1 :(得分:-1)
您正在创建NSManagedObject
个实例The Wrong Way™。使用
- [NSEntityDescription insertNewObjectForEntityForName:... inManagedObjectContext...]
插入新对象。如果要在插入对象时对对象执行自定义处理,请覆盖
- (void)awakeFromInsert
在您的NSManagedObject
子类中。请检查核心数据文档,它明确声明不鼓励您覆盖initWithEntity...
。现在,至于撤消问题,请致电
[delaunay addPoint:CGPointMake(localizacion.x-dummy.bounds.size.width/2, localizacion.y-dummy.bounds.size.height/2)];
...这实际上改变了Core Data对象的任何属性吗?其他实例变量,缓存数组等。不会自动注册撤消。如果您执行更改Core Data对象上的属性,请检查[context undoManager]
是否为零。