2013-11-26 219 views
0

我在UITableView中顯示插入,更新和刪除的數組對象,偶爾我會得到下面的異常,即使我正在小心處理更改。我在GitHub上有完整的代碼示例。與UITableView崩潰

https://github.com/brennanMKE/TableMaddness

此示例項目使用它們實現NSCoding和NSCopying還有的isEqual對象,以便更新與插入,更新和刪除該表可以模擬一下我在這是有同樣的問題一個真正的應用程序正在做。我正在避免使用使用NSFetchedResultsController的Core Data,所以我想知道如果我沒有使用Core Data,我應該使用它。在

斷言故障 - [UITableView的_endCellAnimationsWithContext:],/SourceCache/UIKit_Sim/UIKit-2903.23/UITableView.m:1330 2013年11月25日14:43:20.217 TableMaddness [13411:70B]終止應用程序由於未捕獲異常'NSInternalInconsistencyException',原因:'無效更新:第0節中的行數無效。更新(4)後現有節中包含的行數必須等於更新前該節中包含的行數(4)加上或減去從該部分插入或刪除的行數(插入1個,刪除0個)並加上或減去移入或移出該部分的行數(移入0,移出0)。

下面是相關的代碼。

// determine items which need to be inserted, updated or removed 
    NSMutableArray *inserts = [@[] mutableCopy]; 
    NSMutableArray *deletes = [@[] mutableCopy]; 
    NSMutableArray *reloads = [@[] mutableCopy]; 

    // look for inserts 
    for (NSUInteger row=0; row<fetchedItems.count; row++) { 
     SSTItem *item = fetchedItems[row]; 
     if (![self.currentItems containsObject:item]) { 
      // inserts are items which are not already in self.items 
      [inserts addObject:[NSIndexPath indexPathForRow:row inSection:0]]; 
     } 
     else { 
      NSUInteger otherIndex = [self.currentItems indexOfObject:item]; 
      SSTItem *otherItem = [self.currentItems objectAtIndex:otherIndex]; 
      if (![item.modified isEqualToDate:otherItem.modified]) { 
       [reloads addObject:[NSIndexPath indexPathForRow:row inSection:0]]; 
      } 
     } 
    } 

    // look for deletes 
    for (NSUInteger row=0; row<self.currentItems.count; row++) { 
     SSTItem *item = self.currentItems[row]; 
     if (![fetchedItems containsObject:item]) { 
      [deletes addObject:[NSIndexPath indexPathForRow:row inSection:0]]; 
     } 
    } 

    static NSString *lock = @"LOCK"; 

    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (kDelay/4) * NSEC_PER_SEC), dispatch_get_main_queue(), ^{ 
     // lock is required to prevent inconsistencies when changing view orientation during rotation 
     @synchronized(lock) { 
      self.currentItems = fetchedItems; 

      NSUInteger numberOfRowsInSection = [self tableView:self.tableView numberOfRowsInSection:0]; 
      DebugLog(@"numberOfRowsInSection: %li", numberOfRowsInSection); 
      DebugLog(@"self.items: %li", self.currentItems.count); 

      MAAssert(self.currentItems.count == numberOfRowsInSection, @"Match is required"); 

      if (inserts.count || deletes.count || reloads.count) { 
       [self.tableView beginUpdates]; 
#ifndef NDEBUG 
       for (NSIndexPath *indexPath in inserts) { 
        DebugLog(@"Inserting at %li", (long)indexPath.row); 
       } 
       for (NSIndexPath *indexPath in deletes) { 
        DebugLog(@"Deleting at %li", (long)indexPath.row); 
       } 
       for (NSIndexPath *indexPath in reloads) { 
        DebugLog(@"Reloading at %li", (long)indexPath.row); 
       } 
#endif 
       [self.tableView insertRowsAtIndexPaths:inserts withRowAnimation:UITableViewRowAnimationAutomatic]; 
       [self.tableView deleteRowsAtIndexPaths:deletes withRowAnimation:UITableViewRowAnimationAutomatic]; 
       [self.tableView reloadRowsAtIndexPaths:reloads withRowAnimation:UITableViewRowAnimationAutomatic]; 
       [self.tableView endUpdates]; 
      } 
     } 

     index++; 
     dispatch_after(dispatch_time(DISPATCH_TIME_NOW, kDelay * NSEC_PER_SEC), dispatch_get_main_queue(), ^{ 
      [self runNextUpdate]; 
     }); 
    }); 
+0

在調用'beginUpdates'並執行表更改之前,需要更新表的數據源以反映新的行集。 – rmaddy

+0

@rmaddy此代碼將self.currentItems設置爲fetchedItems在synchronized塊中。我在下面選擇的答案可以防止異常,但我認爲同步塊可以防止這個問題。至少現在我知道這個問題是由於一次運行多個更新引起的。 – Brennan

回答

1
- (void)runNextUpdate { 
if (index >= self.dataSets.count) { 
    index = 0; 

    [self runNextUpdate]; // remove this line 
    return;    // or add this line. 
} 

因爲如果這個條件爲真,你的代碼將運行幾乎在同一時間的兩倍,但數據源尚未更新。

+0

謝謝,這會停止異常,雖然這仍然使用同步塊,應該阻止同時運行2個更新。也許GCD阻止它按照我的預期工作。在該同步塊中,currentItems使用beginUpdates/endUpdates序列進行更新。在真實應用程序中,我將不得不採取措施來處理這種情況,因爲提取可以隨時返回。謝謝您的幫助! – Brennan

+0

不客氣(::感謝您接受答案。是的,我認爲您應該使用GCD而不是@synchronized,比如使用dispatch_group。這篇文章可能對您有所幫助:http://jamiepinkham.com/post/9046964416 /同步異步任務功能於目標c-使用 – Vincent