2010-02-20 69 views
7

我想創建一個iPhone應用程序,用戶可以在其中添加條目。當他按下新條目時,會彈出一個框詢問他一些信息。然後,他可以按「取消」或「保存」丟棄數據或將其保存到磁盤。NSUndoManager撤消不處理核心數據

爲了節省,我使用了Core Data框架,它工作得很好。但是,我無法使「取消」按鈕正常工作。當窗口彈出時,詢問信息,我在託管對象上下文(MOC)中創建一個新對象。然後當用戶按下取消時,我嘗試使用屬於MOC的NSUndoManager。

我也想用嵌套撤消組來做,因爲可能有嵌套組。

爲了測試這個,我寫了一個簡單的應用程序。該應用程序只是啓用了核心數據的「基於窗口的應用程序」模板。對於核心數據模型,我使用整數屬性「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]; 
} 

這個想法很簡單。嘗試插入新的實體對象,撤消它,獲取MOC中的所有實體對象並將其打印出來。如果一切正常,最終應該沒有任何物體。

不過,我得到這樣的輸出:

[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後,我試圖解開它的創作。 關於我在做什麼錯的任何建議?

+0

嗨 我有一個非常相同的問題。你找到解決方案嗎? 您是否嘗試過使用「撤消」而不是「undoNestedGroup」? 謝謝 gonso – gonso 2010-03-09 12:08:36

回答

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; 

} 

做出這樣的轉變之後,不再打印的第二日誌信息。

希望幫助...

戴夫

+2

剛剛找到這個,同時谷歌搜索類似的問題。戴夫,我假設有一個很好的理由,默認情況下,撤消管理器是零?就像,如果我繼續實施這個,我會不會記憶相關的頭痛? – 2010-12-08 04:25:14

4

我想戴夫的做法,但對我沒有工作。 我終於找到了在蘋果公司的例子中,解決方案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; 
} 

我希望它能幫助

Gonso

+0

如果保存失敗會怎麼樣?你將如何撤消已經放入上下文中的變化,然後導致失敗?例如。驗證。 – malhal 2015-12-23 00:51:39

0

它應該工作。你有沒有正確地分配撤銷管理器到你的managedObjectContext?如果你已經正確地做到了這一點,它默認情況下已啓用撤消註冊,你應該很好。關於核心數據here有一篇很好的文章。核心數據和NSUndoManager有一個很好的教程here。希望有所幫助。