3

當我在TabbarController中的兩個選項卡之間切換到包含NSFetchResultsController的Viewcontrollers時。然後NSFetchResultsController -controllerDidChangeContent:嘗試爲userInfo創建兩個單元格的動畫

CoreData: error: Serious application error. An exception was caught from the delegate of NSFetchedResultsController during a call to -controllerDidChangeContent:. Attempt to create two animations for cell with userInfo (null) 

我的tableview變成白色,崩潰,如果我嘗試更新的數據:在我viewcontrollers的一個更新的東西時,我得到了以下核心數據錯誤。

我-controllerDidChangeContent:看起來是這樣的:

  1. 視圖控制器(在我更新的數據視圖 - 控制)。

    -(void)controllerWillChangeContent:(NSFetchedResultsController*)controller 
    { 
    [self.productDetailTableView beginUpdates]; 
    } 
    
    
    -(void)controllerDidChangeContent:(NSFetchedResultsController*)controller 
    { 
    [self.productDetailTableView endUpdates]; 
    } 
    
    
    -(void)controller:(NSFetchedResultsController*)controller didChangeSection:(id<NSFetchedResultsSectionInfo>)sectionInfo atIndex:(NSUInteger)sectionIndex forChangeType:(NSFetchedResultsChangeType)type 
    { 
    
    
    UITableView *tableView = self.productDetailTableView; 
    
    switch (type) { 
        case NSFetchedResultsChangeInsert: 
         [tableView insertSections:[NSIndexSet indexSetWithIndex:sectionIndex] 
                   withRowAnimation:UITableViewRowAnimationFade]; 
         break; 
    
        case NSFetchedResultsChangeDelete: 
         [tableView deleteSections:[NSIndexSet indexSetWithIndex:sectionIndex] 
                   withRowAnimation:UITableViewRowAnimationFade]; 
         break; 
        } 
    } 
    
    -(void)controller:(NSFetchedResultsController*)controller didChangeObject: (id)anObject  atIndexPath:(NSIndexPath*)indexPath forChangeType:(NSFetchedResultsChangeType)type newIndexPath:(NSIndexPath*)newIndexPath 
    { 
    
    UITableView *tableView = self.productDetailTableView; 
    
    NSIndexPath *tvIndexPath = [NSIndexPath indexPathForRow:indexPath.row inSection:(indexPath.section + 1)]; 
    NSIndexPath *tvNewIndexPath = [NSIndexPath indexPathForRow:newIndexPath.row inSection:(newIndexPath.section + 1)]; 
    
    indexPath = tvIndexPath; 
    newIndexPath = tvNewIndexPath; 
    switch (type) { 
        case NSFetchedResultsChangeInsert: 
    
         [tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] 
                     withRowAnimation:UITableViewRowAnimationFade]; 
    
         break; 
    
        case NSFetchedResultsChangeDelete: 
         [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] 
                     withRowAnimation:UITableViewRowAnimationFade]; 
    
         break; 
    
        case NSFetchedResultsChangeMove: 
         [tableView deleteRowsAtIndexPaths:[NSArray 
                  arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationNone]; 
         [tableView insertRowsAtIndexPaths:[NSArray 
                  arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationNone]; 
         break; 
    } 
    } 
    
  2. Viewcontroller(此視圖控制器,其中TableView變白併發生錯誤)。

    -(void)controllerWillChangeContent:(NSFetchedResultsController *)controller { 
    
    [self.cartTableView beginUpdates]; 
    } 
    
    
    -(void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type newIndexPath:(NSIndexPath *)newIndexPath { 
    
    UITableView *tableView = self.cartTableView; 
    
    switch(type) { 
    
        case NSFetchedResultsChangeInsert: 
          [tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationNone]; 
         break; 
    
        case NSFetchedResultsChangeDelete: 
         [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationNone]; 
         break; 
    
        case NSFetchedResultsChangeUpdate: 
         [self configureCell:(ProductCell *)[tableView cellForRowAtIndexPath:indexPath] atIndexPath:indexPath]; 
         break; 
    
        case NSFetchedResultsChangeMove: 
         [tableView deleteRowsAtIndexPaths:[NSArray 
                  arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationNone]; 
         [tableView insertRowsAtIndexPaths:[NSArray 
                  arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationNone]; 
         break; 
    } 
    } 
    
    -(void)controller:(NSFetchedResultsController *)controller didChangeSection:(id)sectionInfo atIndex:(NSUInteger)sectionIndex forChangeType:(NSFetchedResultsChangeType)type { 
    
    UITableView *tableView = self.cartTableView; 
    
    switch(type) { 
    
        case NSFetchedResultsChangeInsert: 
         [tableView insertSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationFade]; 
         break; 
    
        case NSFetchedResultsChangeDelete: 
         [tableView deleteSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationFade]; 
         break; 
        } 
        } 
    
    
    -(void)controllerDidChangeContent:(NSFetchedResultsController *)controller { 
    
    [self.cartTableView endUpdates]; 
    } 
    

怎樣才能解決這個問題,並得到了「嘗試創建兩個動畫細胞與USERINFO」走開,什麼是這種情況出現的原因嗎?

+0

您是否使用兩個視圖控制器相同的NSFetchedResultsController對象? –

+0

沒有2個獨立的NSFetchedResultsControllers。但是同樣的NSMangedObjectContext。 – 7c9d6b001a87e497d6b96fbd4c6fdf

+0

你是否同時更新了兩個視圖控制器? –

回答

1

由於您使用的是相同的NSManagedObject,因此在兩個控制器上數據更改時都會調用didChangeObject。

所以,如果你是第一個視圖控制器上,並添加一個條目,這條線將被調用:

[tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath]              withRowAnimation:UITableViewRowAnimationFade]; 

雖然這個動畫正在發生的事情,在第二個控制器上這條線也將被調用:

[tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationNone]; 

我想這就是爲什麼你會得到一個錯誤。您應該檢查選中的選項卡,並且只在當前選定的控制器上調用beginUpdatesendUpdates,insertRowsAtIndexPathdeleteRowsAtIndexPath

您可以使用獲得當前選定的選項卡:tabBarController.selectedIndex

2

事情來看待:

一),你應該確保NSFetchResultsController的委託是指向正確的視圖控制器;您可能在兩個FRC指向同一個視圖控制器並導致雙重動畫的情況下設置錯誤b)確保通過設置斷點

來調用視圖控制器的controllerWillChangeContent一次(或兩次)

c)請注意您的didChangeObject代碼對於兩個視圖控制器都是不同的?確保你知道indexPaths正在安裝正確

實在不行: - 後置代號就如何FRCS是設置 - 後置代號你如何插入對象插入到的NSManagedObjectContext

3

這不是一個核心數據問題,與核心數據無關。這是一個tableview問題。CoreData正在調用你的委託方法,並且在那裏UIKit拋出一個異常,因爲你試圖對同一個單元格進行兩次動畫處理。

  1. 爲所有異常設置符號斷點並嘗試複製此行爲。請注意,當CoreData解決合併衝突時,它將拋出完全正常的異常,但調試器將停止這些異常。只要繼續下去,直到你的tableview異常。這將縮小哪個表視圖是問題。

  2. 看看驅動您的細胞動畫的數據。從你的代碼看來,你好像在動畫之前修改索引路徑。這可能是問題的一部分。試想一下,如果你有NSFetchedResultsChangeMovetvIndexPath等於tvNewIndexPath。這將產生你正在描述的東西。

CoreData絕對不是這裏的問題,它是你的tableview動畫。 CoreData只是信使。

+0

正確。我目前正在處理一個情況,我們有一個按上次打開的日期排序的文檔列表。當您打開文檔時,核心數據會通知我們該項目已更新(上次打開日期已更改)並移動(更改了排序位置)。簡單地將更新傳遞給tableview觸發了這個斷言,因爲兩個更新都涉及同一個單元。不知道該解決方案是什麼... – n8gray

2

我剛剛在我公司的代碼中解決了這個問題。我必須編寫一個類來清理表視圖中使用的提取結果控制器的輸出。

NSFetchResultsController API與UITableViewController API非常匹配,似乎很明顯它們是如何協同工作的,但是它是一個陷阱!表視圖無法處理提取結果控制器可以生成的所有更新組合。

在我們的案例中,我們顯示按上次打開的日期排序的文檔列表。當您打開文檔時,其dateLastOpened字段發生更改(觸發Update通知),並且其排序列表中的順序發生更改(觸發Move通知)。如果您嘗試在相同的tableView更新中應用這兩個更改,您將觸發臭名昭着的斷言。

因此,我的篩選器類偵聽NSFetchResultsController委託回調並記錄索引路徑。更新完成後,它將Move事件轉換爲Delete加上Add,並刪除任何觸摸移動或刪除的索引路徑的事件Update。所得到的一組更改將作爲批次應用到UITableView

相關問題