1

이전에 discussed here처럼 두 NSFetchedResultsControllers (두 섹션이있는 테이블, 각 NSFetchedResultsControllers에 대해 하나의 섹션)의 결과로 구동되는 UITableView로 UITableViewController를 구현했습니다.UITableView는 두 개의 NSFetchedResultsController가 공통 결과로 구동합니다.

두 코드 모두 NSFetchedResultsController가 공통으로 사용하지 않으면 내 코드가 올바르게 실행되고 오류없이 실행됩니다.

Serious application error. An exception was caught from the delegate of 
NSFetchedResultsController during a call to -controllerDidChangeContent:. 
Invalid update: invalid number of rows in section 0. The number of rows contained in 
an existing section after the update (1) must be equal to the number of rows contained 
in that section before the update (1), plus or minus the number of rows inserted or 
deleted from that section (1 inserted, 0 deleted). with userInfo (null) 

I가 요청하고 있습니다 때마다 내가 출력 해요 : 내 NSFetchedResultsControllers의 모두에서 결과로 보여 코어 데이터 개체를 삽입 할 때

, 나는이 문제로 실행 해요

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { 
    id <NSFetchedResultsSectionInfo> sectionInfo; 
    if (section < [self.fetchedResultsController1.sections count]) { 
     sectionInfo = [[self.fetchedResultsController1 sections] objectAtIndex:section]; 
    } 
    else { 
     sectionInfo = [[self.fetchedResultsController2 sections] objectAtIndex:section-[self.fetchedResultsController1.sections count]]; 
    } 

    NSLog(@"Section %d with %d row(s)", section, [sectionInfo numberOfObjects]); 
    return [sectionInfo numberOfObjects]; 
} 

및 개체 didObject 삽입 도착마다 프린트 아웃 : 섹션의 행 번호

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

    UITableView *tableView = self.tableView; 

    switch(type) { 

     case NSFetchedResultsChangeInsert: 
      NSLog(@"Inserting %@ %@", newIndexPath, anObject); 
      [tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationFade]; 
      break; 

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

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

     case NSFetchedResultsChangeMove: 
      [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade]; 
      // Reloading the section inserts a new row and ensures that titles are updated appropriately. 
      [tableView reloadSections:[NSIndexSet indexSetWithIndex:newIndexPath.section] withRowAnimation:UITableViewRowAnimationFade]; 
      break; 
    } 
} 
,745 I 위의 코드를 실행할 때 1,515,

, I는 상기 오차 (명료 함) 다음과 같은 결과를 얻을 즉시이를 따르

2012-03-28 00:59:55.611 MyApp[517:207] Section 1 with 0 row(s) 
2012-03-28 00:59:55.612 MyApp[517:207] Section 0 with 0 row(s) 
2012-03-28 00:59:55.613 MyApp[517:207] Inserting <NSIndexPath 0x5948150> 2 indexes [0, 0] <MyClass: 0xd60f8b0> (entity: MyClass; id: 0xd611d50 <x-coredata:///MyClass/tD7E0DB3C-4D85-468C-9DD0-BAD0A53B20A310> ; data: { 
    .... 
}) 
2012-03-28 00:59:55.614 MyApp[517:207] Section 0 with 1 row(s) 
2012-03-28 00:59:55.614 MyApp[517:207] Section 1 with 0 row(s) 
2012-03-28 00:59:55.618 MyApp[517:207] Inserting <NSIndexPath 0x5948150> 2 indexes [0, 0] <MyClass: 0xd60f8b0> (entity: MyClass; id: 0xd611d50 <x-coredata:///MyClass/tD7E0DB3C-4D85-468C-9DD0-BAD0A53B20A310> ; data: { 
    .... 
}) 
2012-03-28 00:59:55.619 MyApp[517:207] Section 0 with 1 row(s) 
2012-03-28 00:59:55.620 MyApp[517:207] Section 1 with 1 row(s) 
2012-03-28 00:59:55.620 MyApp[517:207] *** Assertion failure in -[UITableView _endCellAnimationsWithContext:], /SourceCache/UIKit_Sim/UIKit-1448.89/UITableView.m:995 
2012-03-28 00:59:55.621 MyApp[517:207] Serious application error. An exception was caught from the delegate of NSFetchedResultsController during a call to -controllerDidChangeContent:. Invalid update: invalid number of rows in section 0. The number of rows contained in an existing section after the update (1) must be equal to the number of rows contained in that section before the update (1), plus or minus the number of rows inserted or deleted from that section (1 inserted, 0 deleted). with userInfo (null) 

는 그 결과 중복 될 단일 jQuery과 구동 두 NSFetchedResultsControllers를 갖는 아니 좋은 생각? 그것은 받아 들일 수있는 대답이지만 가능한 경우이 오류를 피하기 위해 무엇을 할 수 있습니까?

답변

1

controller:didChangeObject:...에서 발생하는 변경 사항을 [tableView beginUpdates][tableView endUpdates]에서 적절한 NSFetchedResultsControllerDelegate 메서드로 래핑한다고 가정합니다.

각 NSFRC는 beginUpdates, insertCellsendUpdates을 호출합니다. 이 순서대로.

대부분 문제는 tableView가 첫 번째 호출 후 각 섹션의 섹션 수와 행 수를 endUpdates으로 요청한다는 것입니다. 한 섹션의이 지점에서 셀의 양은 tableView:numberOfRowsInSection:의 결과와 일치합니다. 두 번째 fetchedResultsController가 해당 대리자 메서드를 실행하지 않았기 때문에 불행히도 다른 섹션에서 일치하지 않습니다. 따라서 두 번째 NSFRC는 아직 새 셀을 삽입 할 수 없지만 이미 새로운 수의 객체를 반환합니다.

어떻게 해결할 수 있습니까? 나는 세 가지 다른 방법을 생각할 수 있습니다. 첫 번째는 최고이며, 마지막 하나는 완료하지 않아야합니다.

옵션 1 : NSFetchedResultsController가 작동하도록 데이터 모델을 다시 작성하십시오. 2 개의 NSFRC 중 어느 것이 객체가 데이터 모델에 속해 있는지 결정하고 적절한 sectionKeyPath를 설정하는 데 사용하는 속성을 넣으십시오. 하나의 오브젝트가 두 섹션에 동시에있을 수 없기 때문에 두 섹션에 속하는 오브젝트에 세 번째 섹션이 필요할 것입니다.

옵션 2 : NSFetchedResultsController를 덤프하고 NSArrays를 사용하십시오. 핵심 데이터 변경이 다른 곳 (예 : 백그라운드에서 실행되는 가져 오기)에서 발생할 수있는 경우 직접 변경 사항을 추적해야하기 때문에 어려움을 겪을 수 있습니다. 다른 프로세스에서 코어 데이터 객체를 변경하면 알림을 보내야합니다. viewController에서 발생하는 변경 사항도 관리해야합니다. 이전 배열의 복사본을 만들고 새 배열을 가져 와서 배열을 비교하고 적절한 위치에 셀을 삽입하거나 삭제할 수 있습니다.

옵션 3 : 잘못된 코드와 더러운 트릭을 좋아한다면이 의사 코드와 같은 것을 시도 할 수 있습니다.

  • 아이디어가 beginUpdates의 또 다른 세트의 두 섹션에 삽입 또는 삭제의 원인이 모든 변경 사항을 래핑하는 것입니다 controller:didChangeObject:atIndexPath:forChangeType:newIndexPath:

    if (change will cause insert or delete in both sections) { 
    if (!delayEndUpdates) { 
        self.delayEndUpdates = YES 
        self.firstUpdatingController = controller; 
        [tableView beginUpdates]; // another beginUpdates should stop the tableView from updating. At least in theory 
    } 
    } 
    else { 
    self.delayEndUpdates = NO; 
    } 
    
  • [tableView endUpdates]; // the original 
    if (self.firstUpdatingController != controller) { 
    // after the second NSFRC did change its content 
    if (delayEndUpdates) { 
        [tableView endUpdates]; // another one to start tableView updating again 
    } 
    self.firstUpdatingController = nil; 
    } 
    

controllerDidChangeContent:에와 endUpdates. 그러나 이것이 작동하는지 확실하지 않습니다. 설명서에 beginUpdates 및 endUpdates를 중첩시킬 수 있다고 나와 있지만 결코 시도한 적이 없습니다.

+0

내 NSFetchedResultsControllerDelegate 메소드는'[tableView beginUpdates]'와'[tableView endUpdates]'를 호출합니다. 그리고 이것은 또한 사실입니다 : tableView는 섹션의 수와 각 섹션의 행 수를 먼저'endUpdates'를 호출하십시오. 나는 첫 번째 접근법의 수정 된 버전을 따를 것이다. 내 섹션에서 두 가지 다른 정렬 순서가 필요하기 때문에 여전히 두 개의 'NSFetchedResultController's가 필요하다고 생각하지만 두 개의 다른 섹션에서 같은 개체를 사용하지 않아도됩니다. –