NSUndoManager撤消不在iOS上使用Core Data

时间:2011-11-15 07:40:15

标签: objective-c core-data

我在使用复杂模型时遇到NSUndoManager无法撤消的问题。

这是我的模特。

core data model

我有一个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,一旦我点击撤消它就像循环一样永远张贴。好的,现在我知道我必须在某处做错事,但......在哪里?

2 个答案:

答案 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]是否为零。