Objective c NSUndoManager撤消不使用iOS上的核心数据
在处理复杂模型时,我遇到了一个NSUndoManager无法撤消的问题 这是我的模型 我有一个处理核心数据的单例,这是它的初始化:Objective c NSUndoManager撤消不使用iOS上的核心数据,objective-c,core-data,Objective C,Core Data,在处理复杂模型时,我遇到了一个NSUndoManager无法撤消的问题 这是我的模型 我有一个处理核心数据的单例,这是它的初始化: model =[NSManagedObjectModel mergedModelFromBundles:nil]; NSPersistentStoreCoordinator *psc = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:model];
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];
对于每个实体,我都有一个init方法,该方法调用[self initWithEntity…],然后初始化一些属性。这是半边实体的一个示例:
- (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;
}
当用户添加新图形时,我会创建一个新的图形实体,然后让用户在屏幕上添加点。对于每个点,都将执行一个可以添加和/或删除三角形实体、半边和顶点的车辙线。这是电话:
[[[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)
编辑
哇,我刚刚注册了NSUndoManagerCheckpointNotification of undoManager,一旦我点击undo,它就会像循环一样永久发布。好吧,现在我知道我一定在什么地方做错了什么,但是。。。哪里?您正在以错误的方式创建
NSManagedObject
实例™. 使用
- [NSEntityDescription insertNewObjectForEntityForName:... inManagedObjectContext...]
插入新对象。如果要在插入对象时对其进行自定义处理,请替代
- (void)awakeFromInsert
在NSManagedObject
子类中。请检查核心数据文档,它明确表示不鼓励您重写initWithEntity…
。现在,关于撤消问题,请调用
[delaunay addPoint:CGPointMake(localizacion.x-dummy.bounds.size.width/2, localizacion.y-dummy.bounds.size.height/2)];
。。。这实际上会改变核心数据对象上的任何属性吗?其他实例变量、缓存数组等。不会自动注册撤消。如果您确实更改了核心数据对象的属性,请检查
[context undoManager]
是否为空。我发现了。结果我找错地方了
尝试调试NSNDOManager时,我注册了通知,发现NSNDOManagerCheckPointNotification被多次调用
[delaunay addPoint…]对模型进行所有更改。但同时有一个渲染例程正在运行,它将三角形渲染到屏幕上。在这个程序中,我设置了这些三角形的颜色。我需要在那里做这件事,因为我不知道在渲染屏幕背景之前应该用什么颜色
对NSManagedObject子类三角形的color属性所做的这些更改导致NSUndoManagerCheckpointNotification被触发,而undo不起作用。如果我把它去掉,撤销就行了
所以我想我只需要添加这个,这样在渲染过程中所做的更改就不会进入撤销堆栈
[[[DibujosStore sharedStore] managedObjectContext] processPendingChanges];
[[[[DibujosStore sharedStore] managedObjectContext] undoManager] disableUndoRegistration];
[renderer render];
[[[DibujosStore sharedStore] managedObjectContext] processPendingChanges];
[[[[DibujosStore sharedStore] managedObjectContext] undoManager] enableUndoRegistration];
谢谢你的回复。我试试你说的。但我确实读过关于子类化NSManagedObject的文档,正如您所看到的,我实际上并没有覆盖initWithEntity。。。我知道这样做似乎不太正确,但我在某处看到了它,它实际上似乎起了作用,正如我所说的,实体正在被创建并添加到核心数据数据库中。至于awakeFromInsert。。。有没有办法通过这种方式将一些参数传递给初始值设定项?
-insertNewObjectForEntityForName
返回插入的对象,您可以使用它来设置一些初始参数。[context undoManager]
是否为零?[delaunay addPoint:…]
是否实际更改了核心数据对象的属性?您可以发布该方法的代码吗?调用-initWithEntity:insertIntoManagedObjectContext:
不是错误的方法。+insertNewObjectForEntityForName:inManagedObjectContext:
的文档清楚地表明,它在内部执行的操作相当于调用-initWithEntity:InsertingToManagedObjectContext:
。但是文档还声明,不鼓励您重写-initWithEntity:InsertingToManagedObjectContext
。如果苹果公司积极劝阻,我肯定会称之为错误的方式。尤其是当有更容易的方法来完成任务时。