2012-04-24 81 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