7

我正在尝试创建一个 iPhone 应用程序,用户可以在其中添加条目。当他按下一个新条目时,会弹出一个框询问他一些信息。然后他可以按“取消”或“保存”来丢弃数据或将其保存到磁盘。

为了节省,我使用了 Core Data 框架,它工作得很好。但是,我无法让“取消”按钮工作。当弹出窗口询问信息时,我在托管对象上下文 (MOC) 中创建一个新对象。然后当用户按下取消时,我尝试使用属于 MOC 的 NSUndoManager。

我也想使用嵌套的撤消组来做到这一点,因为可能有嵌套组。

为了测试这一点,我编写了一个简单的应用程序。该应用程序只是启用了 Core Data 的“基于窗口的应用程序”模板。对于核心数据模型,我创建了一个名为“Entity”的实体,其整数属性为“x”。然后在 applicationDidFinishLaunching 中,我添加以下代码:

- (void)applicationDidFinishLaunching:(UIApplication *)application {    

  // Override point for customization after app launch    

  unsigned int x=arc4random()%1000;
  [self.managedObjectContext processPendingChanges];
  [self.managedObjectContext.undoManager beginUndoGrouping];

  NSManagedObject *entity=[NSEntityDescription insertNewObjectForEntityForName:@"Entity" 
                                                        inManagedObjectContext:self.managedObjectContext];
  [entity setValue:[NSNumber numberWithInt:x] forKey:@"x"];
  NSLog(@"Insert Value %d",x);

  [self.managedObjectContext processPendingChanges];
  [self.managedObjectContext.undoManager endUndoGrouping];
  [self.managedObjectContext.undoManager undoNestedGroup];

  NSFetchRequest *fetchRequest=[[NSFetchRequest alloc] init];
  NSEntityDescription *entityEntity=[NSEntityDescription entityForName:@"Entity"
                                                inManagedObjectContext:self.managedObjectContext];
  [fetchRequest setEntity:entityEntity];
  NSArray *result=[self.managedObjectContext executeFetchRequest:fetchRequest error:nil];
  for(entity in result) {
    NSLog(@"FETCHED ENTITY %d",[[entity valueForKey:@"x"] intValue]);
  }

    [window makeKeyAndVisible];
}

这个想法很简单。尝试插入一个新的 Entity 对象,撤消它,获取 MOC 中的所有 Entity 对象并将它们打印出来。如果一切正常,最后应该没有对象。

但是,我得到这个输出:

[Session started at 2010-02-20 13:41:49 -0800.]
2010-02-20 13:41:51.695 Untitledundotes[7373:20b] Insert Value 136
2010-02-20 13:41:51.715 Untitledundotes[7373:20b] FETCHED ENTITY 136

如您所见,在我尝试撤消其创建后,该对象存在于 MOC 中。关于我做错了什么的任何建议?

4

3 回答 3

13

您的问题是由以下事实引起的,与 OS X 不同,iPhone 托管对象上下文默认不包含撤消管理器。您需要明确添加一个。

将应用程序委托中为 managedObjectContext 属性生成的代码更改为如下所示:

- (NSManagedObjectContext *) managedObjectContext {

    if (managedObjectContext != nil) {
        return managedObjectContext;
    }

    NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
    if (coordinator != nil) {
        managedObjectContext = [[NSManagedObjectContext alloc] init];
        //add the following 3 lines of code
        NSUndoManager *undoManager = [[NSUndoManager alloc] init];
        [managedObjectContext setUndoManager:undoManager];
        [undoManager release];
        [managedObjectContext setPersistentStoreCoordinator: coordinator];
    }

    return managedObjectContext;

}

进行该更改后,不再打印第二条日志消息。

希望有帮助...

戴夫

于 2010-03-10T23:30:01.980 回答
4

我尝试了戴夫的方法,但对我不起作用。我终于在 Apple 的示例CoreDataBooks中找到了解决方案

诀窍是创建一个与您的应用程序上下文共享协调器的新上下文。要丢弃不需要做的更改,只需丢弃新的上下文对象。由于您共享协调器,因此保存会更新您的主要上下文。

这是我的改编版本,我使用一个静态对象作为临时上下文来创建一个新的 ChannelMO 对象。

//Gets a new ChannelMO that is part of the addingManagedContext
+(ChannelMO*) getNewChannelMO{

    // Create a new managed object context for the new channel -- set its persistent store coordinator to the same as that from the fetched results controller's context.
    NSManagedObjectContext *addingContext = [[NSManagedObjectContext alloc] init];
    addingManagedObjectContext = addingContext;

    [addingManagedObjectContext setPersistentStoreCoordinator:[[self getContext] persistentStoreCoordinator]];

    ChannelMO* aux = (ChannelMO *)[NSEntityDescription insertNewObjectForEntityForName:@"ChannelMO" inManagedObjectContext:addingManagedObjectContext];
    return aux;
}

+(void) saveAddingContext{
    NSNotificationCenter *dnc = [NSNotificationCenter defaultCenter];
    [dnc addObserver:self selector:@selector(addControllerContextDidSave:) 
                name:NSManagedObjectContextDidSaveNotification object:addingManagedObjectContext];

    NSError *error;
    if (![addingManagedObjectContext save:&error]) {
        // Update to handle the error appropriately.
        NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
        exit(-1);  // Fail
    }
    [dnc removeObserver:self name:NSManagedObjectContextDidSaveNotification object:addingManagedObjectContext];

    // Release the adding managed object context.
    addingManagedObjectContext = nil;
}

我希望它有帮助

贡索

于 2010-03-12T20:27:29.587 回答
0

它应该工作。您是否将撤消管理器正确分配给 managedObjectContext?如果你做得对,默认情况下它会启用撤消注册,你应该很高兴。这里有一篇关于核心数据的好文章。这里有一个关于核心数据和 NSUndoManager 的很好的教程。希望有帮助。

于 2012-01-15T17:36:31.400 回答