Objective c NSUndoManager撤消不使用iOS上的核心数据

Objective c NSUndoManager撤消不使用iOS上的核心数据,objective-c,core-data,Objective C,Core Data,在处理复杂模型时,我遇到了一个NSUndoManager无法撤消的问题 这是我的模型 我有一个处理核心数据的单例,这是它的初始化: model =[NSManagedObjectModel mergedModelFromBundles:nil]; NSPersistentStoreCoordinator *psc = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:model];

在处理复杂模型时,我遇到了一个NSUndoManager无法撤消的问题

这是我的模型

我有一个处理核心数据的单例,这是它的初始化:

        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
。如果苹果公司积极劝阻,我肯定会称之为错误的方式。尤其是当有更容易的方法来完成任务时。