2012-03-31 15 views
1

アップルのTable View Animations & Gestures sample appの例に従って、セクションを展開/折りたたむテーブルビューのアプリがあります。閉じたセクションにアイテムが追加されたときに問題に遭遇しています。その後、セクションが開かなくなり、開いて閉じようとすると例外が発生します。行がUITableに挿入されていない

私はオープン/クローズの方法でいくつかの奇妙な行動にこれをトレースしました:

-(void)sectionHeaderView:(SectionHeaderView*)sectionHeaderView sectionOpened:(NSInteger)section { 

if (![[sectionHeaderArray objectAtIndex:section] isOpen]) { 

    [[sectionHeaderArray objectAtIndex:section] setIsOpen:YES]; 

    NSLog(@"self.tableView: %@", self.tableView); 
    id <NSFetchedResultsSectionInfo> sectionInfo = [[self.fetchedResultsController sections] objectAtIndex:section]; 
    NSInteger countOfRowsToInsert = [sectionInfo numberOfObjects]; 

    NSMutableArray *indexPathsToInsert = [[NSMutableArray alloc] init]; 
    for (NSInteger i = 0; i < countOfRowsToInsert; i++) { 
     [indexPathsToInsert addObject:[NSIndexPath indexPathForRow:i inSection:section]]; 
    } 

    // Apply the updates. 
    [self.tableView beginUpdates]; 
    NSLog(@"Count of rows to insert: %d", [indexPathsToInsert count]); 
    NSLog(@"Rows before insert: %d", [self.tableView numberOfRowsInSection:section]); 
    [self.tableView insertRowsAtIndexPaths:indexPathsToInsert withRowAnimation:UITableViewRowAnimationTop]; 
    NSLog(@"Rows after insert: %d", [self.tableView numberOfRowsInSection:section]); 
    [self.tableView endUpdates]; 
} 

} 


-(void)sectionHeaderView:(SectionHeaderView*)sectionHeaderView sectionClosed:(NSInteger)section { 

if ([[sectionHeaderArray objectAtIndex:section] isOpen]) { 

    [[sectionHeaderArray objectAtIndex:section] setIsOpen:NO]; 

    NSInteger countOfRowsToDelete = [self.tableView numberOfRowsInSection:section]; 

    if (countOfRowsToDelete > 0) { 
     NSMutableArray *indexPathsToDelete = [[NSMutableArray alloc] init]; 
     for (NSInteger i = 0; i < countOfRowsToDelete; i++) { 
      [indexPathsToDelete addObject:[NSIndexPath indexPathForRow:i inSection:section]]; 
     } 
     [self.tableView beginUpdates]; 
     NSLog(@"Count of rows to delete: %d", [indexPathsToDelete count]); 
     NSLog(@"Rows before delete: %d", [self.tableView numberOfRowsInSection:section]); 
     [self.tableView deleteRowsAtIndexPaths:indexPathsToDelete withRowAnimation:UITableViewRowAnimationTop]; 
     NSLog(@"Rows after delete: %d", [self.tableView numberOfRowsInSection:section]); 

    } 

    [self.tableView endUpdates]; 
} 
} 

ログメッセージは、(行の挿入)オープンで、> 0行が挿入されていることを示し、まだ行そのセクションのためのカウントは0のまま:

2012-03-31 13:36:17.454 QuickList7[5523:fb03] Count of rows to insert: 3 
2012-03-31 13:36:17.454 QuickList7[5523:fb03] Rows before insert: 0 
2012-03-31 13:36:17.454 QuickList7[5523:fb03] Rows after insert: 0 

これは、テーブルとデータソース間の矛盾した状態を設定し、私は「崩壊」セクションしようとすると、その後、私は次の例外を取得:

2012-03-31 13:48:35.783 QuickList7[5523:fb03] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Invalid table view update. The application has requested an update to the table view that is inconsistent with the state provided by the data source.' 

3行を挿入するにはどうしたら0行で終了するのですか?私はこの種の問題場に走っていたので、私は非常に異なる方法で同様の動作を実現してきた私のアプリで

おかげで、

サーシャ

答えて

1

問題が見つかりました。実際にはfetchedResultsControllerの変更ハンドラにあります。それは、テーブルを悪い状態にして、データソースと同期していないクローズドセクションの変更に対応していました。だから私は、挿入セクションが開いている場合は、行の挿入/削除/更新のみを行うように、各更新のチェックを追加しました。

- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject 
    atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type 
    newIndexPath:(NSIndexPath *)newIndexPath 
{ 
UITableView *tv = self.tView; 
switch(type) { 
    case NSFetchedResultsChangeInsert: 
     if ([[sectionHeaderArray objectAtIndex:newIndexPath.section] isOpen]) { 
      [tv insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationFade]; 
     } 
     break; 

    case NSFetchedResultsChangeDelete: 
     if ([[sectionHeaderArray objectAtIndex:indexPath.section] isOpen]) { 
      [tv deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade]; 
     } 
     break; 

    case NSFetchedResultsChangeUpdate: 
     if ([[sectionHeaderArray objectAtIndex:indexPath.section] isOpen]) { 
      [self configureCell:[tv cellForRowAtIndexPath:indexPath] atIndexPath:indexPath]; 
     } 
     break; 

    case NSFetchedResultsChangeMove: 
     if ([[sectionHeaderArray objectAtIndex:indexPath.section] isOpen]) { 
      [tv deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade]; 
     } 
     if ([[sectionHeaderArray objectAtIndex:newIndexPath.section] isOpen]) { 
      [tv insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath]withRowAnimation:UITableViewRowAnimationFade]; 
     } 
     break; 
} 

} 
+0

それは難しい1つです!私は同じ問題を抱えていて、それが拡大されていないセクションとは何か関係があることを理解するのに数時間かかりました。 –

0

MenuNameCells、MenuItemCellsの表と、下部に静的なセルがあります。一度に1つのメニューしか展開されず、MenuNameCellをタップするとそのメニューが展開または折りたたまれます。私はMenuNameCellを独自のセクションに、MenuItemCellを別のセクションに保持しているので、テーブルをリロードするときにセクション全体を挿入/削除するだけで済む。

ここに私のテーブルのデータソースです:

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView 
{ 
    // number of menus, plus 1 if a menu is open, plus 1 static cell 
    return [self.restaurant.menus count]+(self.menu != nil ? 1 : 0)+1; 
} 

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section 
{ 
    // if this section is our selected menu, return number of items, otherwise return 1 
    int numberOfRowsInSection = ([self indexPathIsInMenuItemSection:section] ? [[self.menu items] count] : 1); 
    return numberOfRowsInSection; 
} 

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 
{ 
    if (indexPath.section == [tableView numberOfSections]-1) { 
     // ... set up and return static cell 
    } 
    if ([self indexPathIsInMenuItemSection:indexPath.section]) { 
     // ... set up and return menu item cell 
    } else { 
     // ... set up and return menu name cell 
    } 
} 

と私のテーブルのデリゲート:私のデータがあるので

- (BOOL)indexPathIsInMenuItemSection:(NSInteger)section 
{ 
    // returns YES if section refers to our MenuItemCells 
    int indexOfMenu = [self.restaurant getIndexOfMenu:self.menu]; 
    return indexOfMenu != -1 && section == indexOfMenu+1; 
} 

- (void)reloadTableView:(UITableView *)tableView withMenu:(Menu *)menu animated:(BOOL)animated autoscroll:(BOOL)autoscroll 
{ 
    int oldIndex = [self.restaurant getIndexOfMenu:self.menu]; 
    int newIndex = [self.restaurant getIndexOfMenu:menu]; 

    [tableView beginUpdates]; 

    if (oldIndex != -1) { 
     // index of [section for items] is oldIndex+1 
     [tableView deleteSections:[NSIndexSet indexSetWithIndex:oldIndex+1] withRowAnimation:UITableViewRowAnimationTop]; 
    } 
    if (newIndex != -1) { 
     // index for [section for items] is newIndex+1 
     [tableView insertSections:[NSIndexSet indexSetWithIndex:newIndex+1] withRowAnimation:UITableViewRowAnimationTop]; 
     [self setMenu:menu]; 
    } else { 
     // no new menu 
     [self setMenu:nil]; 
    } 

    [tableView endUpdates]; 
    if (autoscroll) [self autoscroll]; 
} 

- (void)autoscroll 
{ 
    if (self.menu != nil) { 
     int section = [self.restaurant getIndexOfMenu:self.menu]; 
     if (section != -1) { 
      NSUInteger indexes[] = {section,0}; 
      NSIndexPath *indexPath = [NSIndexPath indexPathWithIndexes:indexes length:2]; 
      [self.tableView scrollToRowAtIndexPath:indexPath atScrollPosition:UITableViewScrollPositionTop animated:YES]; 
     } 
    } 
} 

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath 
{ 
    [tableView deselectRowAtIndexPath:indexPath animated:YES]; 
    // return if it's a static cell 
    if (indexPath.section==[tableView numberOfSections]-1) 
     return; 
    // if it's a menu name cell, close open menu and maybe expand this menu 
    if (![self indexPathIsInMenuItemSection:indexPath.section]) { 
     BOOL reset = self.menu == m; 
     if (reset) [self reloadTableView:self.tableView withMenu:nil animated:YES autoscroll:NO]; 
     else [self reloadTableView:self.tableView withMenu:m animated:YES autoscroll:YES]; 
    } 
} 

そこに記載されたヘルパーのカップルがありました非同期的に他の場所にロードされ、私はNSNotificationを受け取るようにこのコントローラを設定しましたが、うまくいくはずですこれを呼び出すだけでもviewDidAppear

[self reloadTableView:self.tableView withMenu:self.menu animated:YES autoscroll:YES]; 

私はこれが役立つことを願っています。もし私がそれを明らかにすることができたら教えてください。

+0

ありがとうスペンサー!これは、Appleのサンプルコードを見つける前に、私がこれを実装する必要があるとおおよそのことです。タイトルセルとコンテンツセルを別々のセクションに置くことは考えていませんでしたが、良いアイデアです。私は私のアプローチを変える前に、誰かが他の提案をしているかどうかを知るために掛かっていると思う(私は怠け者だから:)。しかし、私は書き直す必要がある場合、これをテンプレートとして間違いなく使用します。ありがとう! – Sasha

関連する問題