1

NSFetchedResultsController가 첨부 된 UITableView가 있습니다. FRC의 대리자 메서드는 완벽하게 작동하지만 모든 것이 좋지만 셀의 셀 위치에 따라 사용자 지정 배경이 있습니다. 1. UITableView 맨 위에 둥근 모서리가있는 배경 2. 중간에 둥근 모서리 없음) 3. 하단 (둥근 모서리가 아래쪽에 있음) 4. 단일 셀 (모든 모서리가 둥글다). 내 셀 구성 방법에서 셀의 위치를 ​​계산하고 적절한 배경보기를 설정하고 있습니다. 모든 것이 잘 작동하지만 FRC의 대리자 메서드의 구현에 문제가있는 것입니다 :NSFetchedResultsController의 대리자 메서드 처리

- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject 
     atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type 
     newIndexPath:(NSIndexPath *)newIndexPath 
{ 

    UITableView *tableView = self.agenciesTableView; 

    switch(type) 
    { 
     case NSFetchedResultsChangeInsert: 
     { 
      [tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] 
          withRowAnimation:UITableViewRowAnimationNone]; 
      break; 
     } 
     case NSFetchedResultsChangeDelete: 
     { 
      [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] 
          withRowAnimation:UITableViewRowAnimationNone]; 
      break; 
     } 
     case NSFetchedResultsChangeUpdate: 
     { 
      [tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade]; 

      break; 
     } 
     case NSFetchedResultsChangeMove: 
     { 

      [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] 
          withRowAnimation:UITableViewRowAnimationFade]; 
      [tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] 
          withRowAnimation:UITableViewRowAnimationFade]; 
      break; 
     } 
    }; 
} 

당신은 완전히 일반적이지만, 하나의 문제가 볼 수 있듯이 : 셀이 jQuery과의 정상에 삽입됩니다 경우 그것의 구성 메소드 (cellForRowAtIndexPath)가 호출되면 올바르게 (둥근 꼭짓점을 사용하여) 그려 지지만 그 아래에있는 셀 (이전에 상단에 있던 셀)은 둥근 모서리가 둥근 채로 있고 어떻게 든 다시 그릴 필요가 있습니다.

- = EDITED = -

내가 업데이트 논리를 반영하기 위해 FRC의 대리자 메서드를 변경 :

- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject 
     atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type 
     newIndexPath:(NSIndexPath *)newIndexPath 
{ 

    UITableView *tableView = self.agenciesTableView; 

    switch(type) 
    { 
     case NSFetchedResultsChangeInsert: 
     { 
      [tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] 
          withRowAnimation:UITableViewRowAnimationNone]; 

      //if we inserting a cell not to the middle of table view 
      //we need to update the previous cell (if we are inserting to the end) 
      // or the next cell (if we are inserting to the beggining) 
      if ([self controller:controller positionForCellAtIndexPath:newIndexPath]!=UITableViewCellPositionMiddle) 
      { 
       NSIndexPath *prevIndexPath=[NSIndexPath indexPathForRow:(newIndexPath.row+1) inSection:newIndexPath.section]; 
       NSIndexPath *nextIndexPath=[NSIndexPath indexPathForRow:(newIndexPath.row-1) inSection:newIndexPath.section]; 
       if ([self controller:controller cellExistsAtIndexPath:prevIndexPath]) 
       { 
        [tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:prevIndexPath] withRowAnimation:UITableViewRowAnimationNone]; 
       }; 
       if ([self controller:controller cellExistsAtIndexPath:nextIndexPath]) 
       { 
        [tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:nextIndexPath] withRowAnimation:UITableViewRowAnimationNone]; 
       }; 
      }; 
      break; 
     } 
     case NSFetchedResultsChangeDelete: 
     { 
      [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] 
          withRowAnimation:UITableViewRowAnimationNone]; 

      //if we deleting a cell not fromo the middle of table view 
      //we need to update the previous cell (if we are deleting from the end) 
      //or the next cell (if we are deleting from the beggining) 
      if ([self controller:controller positionForCellAtIndexPath:indexPath]!=UITableViewCellPositionMiddle) 
      { 
       NSIndexPath *prevIndexPath=[NSIndexPath indexPathForRow:(indexPath.row+1) inSection:indexPath.section]; 
       NSIndexPath *nextIndexPath=[NSIndexPath indexPathForRow:(indexPath.row-1) inSection:indexPath.section]; 
       if ([self controller:controller cellExistsAtIndexPath:prevIndexPath]) 
       { 
        [tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:prevIndexPath] withRowAnimation:UITableViewRowAnimationNone]; 
       }; 
       if ([self controller:controller cellExistsAtIndexPath:nextIndexPath]) 
       { 
        [tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:nextIndexPath] withRowAnimation:UITableViewRowAnimationNone]; 
       }; 
      }; 
      break; 
     } 
     case NSFetchedResultsChangeUpdate: 
     { 
      [tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationNone]; 

      break; 
     } 
     case NSFetchedResultsChangeMove: 
     { 

      [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] 
          withRowAnimation:UITableViewRowAnimationNone]; 
      if ([self controller:controller positionForCellAtIndexPath:indexPath]!=UITableViewCellPositionMiddle) 
      { 
       NSIndexPath *prevIndexPath=[NSIndexPath indexPathForRow:(indexPath.row+1) inSection:indexPath.section]; 
       NSIndexPath *nextIndexPath=[NSIndexPath indexPathForRow:(indexPath.row-1) inSection:indexPath.section]; 
       if ([self controller:controller cellExistsAtIndexPath:prevIndexPath]) 
       { 
        [tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:prevIndexPath] withRowAnimation:UITableViewRowAnimationNone]; 
       }; 
       if ([self controller:controller cellExistsAtIndexPath:nextIndexPath]) 
       { 
        [tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:nextIndexPath] withRowAnimation:UITableViewRowAnimationNone]; 
       }; 
      }; 


      [tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] 
          withRowAnimation:UITableViewRowAnimationNone]; 
      if ([self controller:controller positionForCellAtIndexPath:newIndexPath]!=UITableViewCellPositionMiddle) 
      { 
       NSIndexPath *prevIndexPath=[NSIndexPath indexPathForRow:(newIndexPath.row+1) inSection:newIndexPath.section]; 
       NSIndexPath *nextIndexPath=[NSIndexPath indexPathForRow:(newIndexPath.row-1) inSection:newIndexPath.section]; 
       if ([self controller:controller cellExistsAtIndexPath:prevIndexPath]) 
       { 
        [tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:prevIndexPath] withRowAnimation:UITableViewRowAnimationNone]; 
       }; 
       if ([self controller:controller cellExistsAtIndexPath:nextIndexPath]) 
       { 
        [tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:nextIndexPath] withRowAnimation:UITableViewRowAnimationNone]; 
       }; 
      }; 
      break; 
     } 
    }; 
} 

그러나이 경우 내가 오류 받고 있어요

:

2013-05-24 21:04:19.458 PharmaTouch[6994:fb03] *** Assertion failure in -[_UITableViewUpdateSupport _computeRowUpdates], /SourceCache/UIKit_Sim/UIKit- 1912.3/UITableViewSupport.m:386 
2013-05-24 21:04:19.483 PharmaTouch[6994:fb03] CoreData: error: Serious application error. An exception was caught from the delegate of NSFetchedResultsController during a call to -controllerDidChangeContent:. 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. with userInfo (null) 

을 - = EDITED2 = - 여기 내 컨트롤러가 있습니다 : cellExistsAtIndexPath : 메소드 구현. 범위를 벗어난 indexPath 인수로 reloadRowsAtIndexPaths 호출을 피하기 위해 안전성 검사에 사용됩니다.

-(BOOL)controller:(NSFetchedResultsController *)controller cellExistsAtIndexPath:(NSIndexPath *)indexPath 
{ 
    if (indexPath.row<0) 
    { 
     return NO; 
    }; 

    NSInteger numberOfRows = 0; 
    NSArray *sections = controller.sections; 
    if(sections.count > 0) 
    { 
     id <NSFetchedResultsSectionInfo> sectionInfo = [sections objectAtIndex:indexPath.section]; 
     numberOfRows = [sectionInfo numberOfObjects]; 
    }; 
    if (indexPath.row>(numberOfRows-1)) 
    { 
     return NO; 
    } 
    else 
    { 
     return YES; 
    }; 
} 

답변

0

나는 controllerWillChangeContent 사이에 업데이트해야하는 행을 유지하는 속성 @property (nonatomic, retain) NSMutableSet *indexPathsForRowsToReloadAfterFRCUpdates;을 추가하여 문제를 해결했습니다.

#pragma mark - NSFetchedResultsControllerDelegate 

- (void)controllerWillChangeContent:(NSFetchedResultsController *)controller 
{ 
    self.indexPathsForRowsToReloadAfterFRCUpdates=[[NSMutableSet alloc] init]; 
    [self.agenciesTableView beginUpdates]; 
} 


- (void)controller:(NSFetchedResultsController *)controller didChangeSection:(id <NSFetchedResultsSectionInfo>)sectionInfo atIndex:(NSUInteger)sectionIndex forChangeType:(NSFetchedResultsChangeType)type 
{ 

    UITableView *tableView = self.agenciesTableView; 

    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.agenciesTableView; 

    switch(type) 
    { 
     case NSFetchedResultsChangeInsert: 
     { 
      [tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] 
          withRowAnimation:UITableViewRowAnimationNone]; 

      //if we inserting a cell not to the middle of table view 
      //we need to update the previous cell (if we are inserting to the end) 
      // or the next cell (if we are inserting to the beggining) 
      if ([self controller:controller positionForCellAtIndexPath:newIndexPath]!=UITableViewCellPositionMiddle) 
      { 
       NSIndexPath *prevIndexPath=[NSIndexPath indexPathForRow:(newIndexPath.row-1) inSection:newIndexPath.section]; 
       NSIndexPath *nextIndexPath=[NSIndexPath indexPathForRow:(newIndexPath.row+1) inSection:newIndexPath.section]; 
       if ([self controller:controller cellExistsAtIndexPath:prevIndexPath]) 
       { 
        [self.indexPathsForRowsToReloadAfterFRCUpdates addObject:prevIndexPath]; 
       }; 
       if ([self controller:controller cellExistsAtIndexPath:nextIndexPath]) 
       { 
        [self.indexPathsForRowsToReloadAfterFRCUpdates addObject:nextIndexPath]; 
       }; 
      }; 
      break; 
     } 
     case NSFetchedResultsChangeDelete: 
     { 
      [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] 
          withRowAnimation:UITableViewRowAnimationNone]; 

      //if we deleting a cell not fromo the middle of table view 
      //we need to update the previous cell (if we are deleting from the end) 
      //or the next cell (if we are deleting from the beggining) 
      if ([self controller:controller positionForCellAtIndexPath:indexPath]!=UITableViewCellPositionMiddle) 
      { 
       NSIndexPath *prevIndexPath=[NSIndexPath indexPathForRow:(indexPath.row) inSection:indexPath.section]; 
       NSIndexPath *nextIndexPath=[NSIndexPath indexPathForRow:(indexPath.row+1) inSection:indexPath.section]; 
       if ([self controller:controller cellExistsAtIndexPath:prevIndexPath]) 
       { 
        [self.indexPathsForRowsToReloadAfterFRCUpdates addObject:prevIndexPath]; 
       }; 
       if ([self controller:controller cellExistsAtIndexPath:nextIndexPath]) 
       { 
        [self.indexPathsForRowsToReloadAfterFRCUpdates addObject:nextIndexPath]; 
       }; 
      }; 
      break; 
     } 
     case NSFetchedResultsChangeUpdate: 
     { 
      [tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationNone]; 

      break; 
     } 
     case NSFetchedResultsChangeMove: 
     { 
      [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] 
          withRowAnimation:UITableViewRowAnimationNone]; 

      if ([self controller:controller positionForCellAtIndexPath:indexPath]!=UITableViewCellPositionMiddle) 
      { 
       NSIndexPath *prevIndexPath=[NSIndexPath indexPathForRow:(indexPath.row) inSection:indexPath.section]; 
       NSIndexPath *nextIndexPath=[NSIndexPath indexPathForRow:(indexPath.row+1) inSection:indexPath.section]; 
       if ([self controller:controller cellExistsAtIndexPath:prevIndexPath]) 
       { 
        [self.indexPathsForRowsToReloadAfterFRCUpdates addObject:prevIndexPath]; 
       }; 
       if ([self controller:controller cellExistsAtIndexPath:nextIndexPath]) 
       { 
        [self.indexPathsForRowsToReloadAfterFRCUpdates addObject:nextIndexPath]; 
       }; 
      }; 


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

      if ([self controller:controller positionForCellAtIndexPath:newIndexPath]!=UITableViewCellPositionMiddle) 
      { 
       NSIndexPath *prevIndexPath=[NSIndexPath indexPathForRow:(newIndexPath.row-1) inSection:newIndexPath.section]; 
       NSIndexPath *nextIndexPath=[NSIndexPath indexPathForRow:(newIndexPath.row+1) inSection:newIndexPath.section]; 
       if ([self controller:controller cellExistsAtIndexPath:prevIndexPath]) 
       { 
        [self.indexPathsForRowsToReloadAfterFRCUpdates addObject:prevIndexPath]; 
       }; 
       if ([self controller:controller cellExistsAtIndexPath:nextIndexPath]) 
       { 
        [self.indexPathsForRowsToReloadAfterFRCUpdates addObject:nextIndexPath]; 
       }; 
      }; 

      break; 
     } 
    }; 
} 


- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller 
{ 
    [self.agenciesTableView endUpdates]; 


    if ([self.indexPathsForRowsToReloadAfterFRCUpdates count]>0) 
    { 
     [self.agenciesTableView reloadRowsAtIndexPaths:[[self.indexPathsForRowsToReloadAfterFRCUpdates allObjects] copy] withRowAnimation:UITableViewRowAnimationNone]; 
    }; 
    self.indexPathsForRowsToReloadAfterFRCUpdates=nil; 

} 
2

모든 행이 새로 고쳐집니다 때문에 당신은뿐만 아니라 단지 reloadData하고 올바르게 수행 될 수 UITableViewRowAnimationNone을 사용하고있다.

UITableViewRowAnimationFade을 사용하고, ... 당신이 그것을 가치를 얼마나 당신은 좀 더 포괄적 인 수표 및 다시로드에서해야 것

을 고려하십시오. 특히 변경중인 섹션에 대해서는 FRC에서 섹션 정보를 가져와야합니다. 들어오는 행 또는 나가는 행이 처음 또는 마지막 행이면 둘 이상의 행을 새로 고쳐야합니다. 의 라인을 따라 : controllerDidChangeContent : 메소드 호출 (FRC 위임 업데이트주기에서)

if first is changing and count > 1, also refresh second 
if last is changing and count > 1, also refresh first 
+0

내 대답을 편집했습니다. 확인하십시오. – user1897723

+0

cellExistsAtIndexPath 란 무엇입니까? – Wain

+0

이 cellExistsAtIndexPath를 추가했습니다. 구현 – user1897723