2012-04-24 77 views
2

我有一个名为appointment的NSManagedObject,我编辑的属性。如果我用户按取消我想要反转所有这些编辑。如何使用撤消管理器与核心数据实体

如果我这样做(例如代码)

[[appointment managedObjectContext] setUndoManager:[[NSUndoManager alloc] init]]; //however doing a nslog on undoManager still shows it as (null); 
[[[appointment managedObjectContext] undoManager] beginUndoGrouping]; 
appointment.startTime = 11; 
appointment.endTime = 12; 
appointment.customer = @"Tom"; 
[[[appointment managedObjectContext] undoManager] endUndoGrouping]; 
[[[appointment managedObjectContext] undoManager] undo]; 

它不应该撤消beginUndoGroupingendUndoGrouping之间的所有变化而变化?似乎有很多方法可以做到这一点,但我似乎无法找到正确的方法。在NSManagedObject上撤销更改的正确方法是什么?

回答

7

我想这只是一个事件顺序的例子,而不是一个实际的例子。

你有没有偶然忘记给ManagedObjectContext一个NSUndoManager?

我相信你会得到一个默认情况下在OS X下,但在iOS下,你必须专门提供一个。

你要确保当您创建MOC设置撤消管理...

managedObjectContext.undoManager = [[NSUndoManager alloc] init]; 

如果撤消经理是零,这样做后,那么你正在使用多个MOCS,或一些其他代码已将其重置。

另外,出于调试的目的,请检查appointment.managedObjectContext属性,并确保它不为零并引用有效的MOC。

编辑

好吧,我只是去写了一个快速测试,用一个简单的模型。也许你应该做类似的事情,看看你的断言失败的地方(你可以在你的代码路径中添加正常的断言 - 我做了一个单元测试,所以我可以轻松地将它添加到现有的项目)。

- (void)testUndoManager 
{ 
    NSDate *now = [NSDate date]; 
    NSManagedObjectContext *moc = [self managedObjectContextWithConcurrencyType:NSConfinementConcurrencyType]; 
    STAssertNil(moc.undoManager, @"undoManager is nil by default in iOS"); 
    moc.undoManager = [[NSUndoManager alloc] init]; 
    [moc.undoManager beginUndoGrouping]; 
    NSManagedObject *object = [NSEntityDescription insertNewObjectForEntityForName:EVENT_ENTITY_NAME inManagedObjectContext:moc]; 
    STAssertNotNil(moc, @"Managed Object is nil"); 
    STAssertEquals(moc, object.managedObjectContext, @"MOC of object should be same as MOC"); 
    STAssertNotNil(object.managedObjectContext.undoManager, @"undoManager of MOC should not be nil"); 
    [object setValue:now forKey:@"timestamp"]; 
    STAssertEqualObjects(now, [object valueForKey:@"timestamp"], @"Timestamp should be NOW"); 
    [moc.undoManager endUndoGrouping]; 
    STAssertEqualObjects(now, [object valueForKey:@"timestamp"], @"Timestamp should be NOW"); 
    [moc.undoManager undo]; 
    STAssertNil([object valueForKey:@"timestamp"], @"Object access should be nil because changes were undone"); 
} 

EDIT

被管理对象的MOC可以几种条件下被设置为零。例如,如果你删除了一个对象,然后保存国防部,商务部将被设置为无该对象...

NSManagedObject *object = [NSEntityDescription insertNewObjectForEntityForName:@"SomeEntity" inManagedObjectContext:moc]; 
[object.managedObjectContext deleteObject:object]; 
[moc save:0]; 
// object.managedObjectContext will be nil 

另一个不那么常见的情况,但一个迹象,表明有可能是内存问题与MOC ...在ARC下,被管理对象的MOC是一个弱指针。因此,如果MOC消失,该指针将被重置为零。在非ARC的情况下,指针只会有旧的值,并且您的结果将不确定...可能是崩溃。

所以,如果managedObject。managedObjectManager为零,最有可能的罪魁祸首是:

  1. 对象从来没有插入MOC
  2. 的对象是从MOC
  3. 的MOC被删除
+0

是的,这是一个例子。事实上,我做了一个setUndoManager,但是这样做后它仍然为空。 – Bot 2012-04-24 22:01:23

+0

你有没有在文档中提到在iOS下说的地方,你必须明确地提供一个撤销管理器? – 2016-10-06 18:21:56

+0

确定我的一位同事找到了引用:https://developer.apple.com/reference/coredata/nsmanagedobjectcontext/1506663-undomanager – 2016-10-06 18:42:57

0

最大的原因,删除撤消不起作用核心数据不创建和设置撤消管理器...

newManager = [[[NSUndoManager alloc] init] autorelease]; 
[newManager setLevelsOfUndo:4]; 
myManagedObjectContext.undoManager = newManager; 

你也d不需要开始/结束撤销分组,因为这是为您完成的。

这也是可能的(部分原因是因为这样做)撤消功能将不起作用,直到你回到事件循环并在下次被调用。 (换句话说,切断用户点击撤消按钮可能不起作用。)

啊,你刚才添加了上面的注释。请发布设置的代码,因为您的撤销管理器为空会显​​然无法使用。

+0

如果在你的setUndoManager,NSLog(“%@”,[[appointment managedObjectContext] undoManager])之后修改了我的OP,并更新了代码 – Bot 2012-04-24 22:27:48

+0

;显示nil,那么约会或appointment.managedObjectContext是否为零? – mackworth 2012-04-24 22:43:17

+0

约会不是零,因为我在其他地方使用它的数据。我敢打赌,managedObjectContext是零。我应该如何设置它? 'appointment.managedObjectContext = [[CoreDataHelper sharedInstance] managedObjectContext];'? – Bot 2012-04-24 22:52:21