1

관련 코어 데이터 엔티티가 변경 될 때마다 NSFetchedResultsController를 표준 방식으로 사용하여 UITableView를 업데이트합니다. 나는 in the Apple documentation와 똑같이하고있다.NSFetchedResultsController 너무 많은 UITableViewCell을 할당하는 위임

내가 가진 문제는 새로운 코어 데이터 엔티티를 대량 삽입 할 때의 문제입니다. 이로 인해 NSFetchedResultsController 델리게이트가 각 엔티티에 새 셀을 할당 (삽입)하지만 UITableViewCell을 재활용하지 않고이 작업을 수행합니다 (즉, dequeueReusableCellWithIdentifier:은 항상 null을 반환합니다). 즉 잠재적으로 100 개의 UITableViewCells 할당을 의미하며 이로 인해 메모리 문제가 발생할 수 있습니다. 누구나 수정 또는 해결 방법을 알고 있습니까? 감사.

편집 1 : 내있는 UITableViewController 하위 클래스 내에서

나는 표준 NSFetchedResultsControllerDelegate 방법이있다. 나는 이것이 애플의 예와 동일하다고 생각한다. 내가 무슨 일이 일어나고 있는지 표시 NSLog 문을 추가

-(void)configureCell:(UITableViewCell *)cell atIndexPath:(NSIndexPath *)indexPath { 
    Waypoint *waypoint = [self.fetchedResultsController objectAtIndexPath:indexPath]; 
    cell.textLabel.text = [waypoint comment]; 
} 

-(UITableViewCell *)tableView:(UITableView *)aTableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {  
    static NSString *CellIdentifier = @"WaypointCell"; // matches identifier in XIB 

    UITableViewCell *cell = [aTableView dequeueReusableCellWithIdentifier:CellIdentifier]; 
    if (cell == nil) { 
     NSLog(@"new cell"); 
     cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];  
     cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator; 
    } else { 
     NSLog(@"recycled cell");  
    } 

    [self configureCell:cell atIndexPath:indexPath]; 

    return cell; 
} 

tableView:cellForRowAtIndexPath: 함수에서 :

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

    UITableView *tableView = self.tableView; 

    switch(type) { 

     case NSFetchedResultsChangeInsert: 
      [tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationTop]; 
      break; 

     case NSFetchedResultsChangeDelete: 
      [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationBottom]; 
      break; 

     case NSFetchedResultsChangeUpdate: 
      [self configureCell:[tableView cellForRowAtIndexPath:indexPath] atIndexPath:indexPath]; 
      break; 

     case NSFetchedResultsChangeMove: 
      [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationBottom]; 
      // Reloading the section inserts a new row and ensures that titles are updated appropriately. 
      [tableView reloadSections:[NSIndexSet indexSetWithIndex:newIndexPath.section] withRowAnimation:UITableViewRowAnimationTop]; 
      break; 
    } 
} 

-(void)controller:(NSFetchedResultsController *)controller didChangeSection:(id <NSFetchedResultsSectionInfo>)sectionInfo atIndex:(NSUInteger)sectionIndex forChangeType:(NSFetchedResultsChangeType)type { 
    switch(type) {   
     case NSFetchedResultsChangeInsert: 
      [self.tableView insertSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationTop]; 
      break; 

     case NSFetchedResultsChangeDelete: 
      [self.tableView deleteSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationBottom]; 
      break; 
    } 
} 

-(void)controllerDidChangeContent:(NSFetchedResultsController *)controller { 
    // The fetch controller has sent all current change notifications, so tell the table view to process all updates. 
    [self.tableView endUpdates]; 
} 

또한 내있는 UITableViewController 하위 클래스에서 나는 주어진 indexPath의 세포를 가져 오는에 대해 다음 있습니다.

여기에 있습니다. 위에서 언급 한 UITableViewController는 탐색 스택에 푸시됩니다. 비동기 요청이 나가고 많은 데이터를 가져오고이 fetchController와 관련된 데이터를 만들거나 수정합니다. [self.tableView endUpdates]이 호출되면 시스템은 UITableViewCell을 만들고 UITableView에 삽입하기 시작합니다. 디버거 콘솔에서 "new cell"출력이 여러 번 인쇄됩니다 (100 번으로 표시 할 수 있음). 생성 된 각각의 새 엔티티에 대해 하나라고 생각합니다. tableview가로드 된 후에 만 ​​(메모리 문제로 인해 충돌이 발생하지 않은 경우) 스크롤을 시작하면 콘솔에 "recycled cell"출력이 표시됩니다.

+0

그리고 그들 중 누구도은 허용 대답이 없다 : 구현의 세부 사항은 다음 포럼 게시물에서 찾을 수 있습니다. 대답이 문제를 해결하면 녹색 기호를 클릭하여 대답을 수락해야합니다. :) – Florin

+0

코드를 보여줘야합니다. 이는 정상적인 동작이 아닙니다. 델리게이트 자체는 셀을 만들지 않습니다. 당신은 부적절하게 어딘가에 세포를 삽입하고 있습니다. – TechZen

+0

플로린 : 적절한 부분을 다시 읽고 업데이트하겠습니다. 헤드 업에 감사드립니다. TechZen : 원래 게시물에 몇 가지 코드를 추가했습니다. 나는 그 문제에 대해 밝히기를 희망한다. 원래는 .xib와 함께 사용자 정의 tableviewcell을 사용했지만 표준 UITableViewCell을 사용하도록 코드를 단순화했으며 동작은 완전히 동일합니다. 대리자가 셀을 만들지 못하도록 수정합니다.이 작업을 수행하는 대리자의 [tableView endUpdates] 호출입니다. 감사. – chris

답변

1

나는 해결책을 발견했다. 문제는 NSFetchedResultsController 자체가 아니며 NSFetchedResultsController 대리자로부터 [tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationTop] 번을 잠재적으로 수백 번 호출합니다.

내 해결책은 NSFetchedResultsController가 위와 같이 새 테이블 행을 삽입해야하는지 또는 대신 [tableView reloadData]을 단순하게 수행할지 여부를 제어하는 ​​massUpdate 부울을 소개하는 것입니다. 삽입 할 행 수에 따라이 값을 설정합니다. 난 그냥 당신이 4 개 질문의 총을 가지고 것으로 나타났습니다

https://devforums.apple.com/message/181219#181219

+1

새 프로젝트를 작업하면서 NSFetchedResultsControllerDelegate 메소드 아래의 Apple RootViewController.m 템플릿 파일에서 다음 주석을 발견했습니다. "개별 변경 사항에 대한 응답으로 테이블 뷰를 업데이트하기위한 위의 메소드 구현은 많은 변경 사항이있을 경우 성능에 영향을 줄 수 있습니다 이것이 문제가되는 경우, 대신에 controllerDidChangeContent :를 구현하여 위임자에게 모든 섹션 및 객체 변경이 처리되었음을 알릴 수 있습니다. " 이것이 알려진 문제인 것처럼 보입니다. – chris

+0

사과에서 발췌 한 부분은 어디에서 찾을 수 있습니까? 감사! – jpswain

+0

XCode와 함께 제공되는 프로젝트 템플릿에서이 파일을 찾았습니다. 새 프로젝트를 만들고 마스터 - 세부 응용 프로그램을 선택하고 코어 데이터 사용이 선택되어 있는지 확인하십시오. MasterViewController.m에서 주석을 찾을 수 있습니다. – chris

1

셀 생성 및 큐 해제에 모두 동일한 식별자를 사용하고 있습니까? (dequeueReusableCellWithIdentifier:과 동일한 식별자)

+0

나는 그게 정확하다는 것을 확신한다. NSLog 문을 여러 위치에 배치하여 동작을 모니터하고 정상적인 테이블 탐색 (위아래로 스크롤)에서 모든 것이 올바르게 작동합니다. 테이블로드시에는 5 또는 6 셀의 초기 할당이 표시되고 위아래로 스크롤하면 다시 사용됩니다. 그것은 100 대가 할당 된 것을 알 수있는 대용량 테이블 업데이트 (원래 설명 된 문제)를 통해서만 가능합니다. 또한 대량 할당 후에 대부분 할당이 해제됩니다. 스크롤이 예상되는 동작으로 돌아 가기 때문에 이것이 보이지 않는 테이블 셀이라고 가정합니다. – chris