6

NSFetchedResultsControllerテーブルビューのデータを更新するためにを使用しています。データ自体は、バックグラウンドで実行されるXMLパーサーを介して提供されます。パーサーが終了すると、データを独自のコンテキストに保存します。はNSFetchedResultsControllerこれらの変更をすぐに取得し、-(void)controller:didChangeObject:atIndexPath:forChangeType:newIndexPath:更新された要素ごとにデリゲートメソッドの呼び出しを開始します。これも高速で、ログファイルでは完全に正常に見えます。

ただし、私は's-(void)controllerDidChangeContent:と呼びます。次に、画面に更新アニメーションが表示されますが、すべてのセルで、半分しか表示されていない最後のセルのほかに、セルの左側にある画像だけが表示されます。すべてのテキストラベルが表示されるわけではありません。約5〜10秒かかり、その後すべてのラベルが表示されます。UITableView-(void)endUpdates

ただし、のすべてのデリゲート呼び出しを無視して、すべてを呼び出すNSFetchedResultsControllerだけで問題なく機能します。コンテンツはすぐにあります。[self.tableView reloadData]-(void)controllerDidChangeContent:

私がここで間違っていることを誰かが知っていますか?プロファイラーは、メインスレッドが基本的に何もしていないことを示しています。テーブルビューにディスパッチされるイベントに加えて、タッチイベントは適切に処理されます。これらは処理されません。テーブルビューは真面目な仕事をしているようですが、アニメーションはすでに終わっているので、それが何であるかは本当にわかりません。

これが私の実装ですNSFetchedResultsControllerDelegate

- (void)controllerWillChangeContent:(NSFetchedResultsController *)controller {
    NSLog(@"%s", __PRETTY_FUNCTION__);
    [self.tableView beginUpdates];
}

- (void)controller:(NSFetchedResultsController *)controller didChangeSection:(id <NSFetchedResultsSectionInfo>)sectionInfo atIndex:(NSUInteger)sectionIndex forChangeType:(NSFetchedResultsChangeType)type {
    NSLog(@"%s", __PRETTY_FUNCTION__);
    switch(type) {
        case NSFetchedResultsChangeInsert:
            [self.tableView insertSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationAutomatic];
            break;
        case NSFetchedResultsChangeDelete:
            [self.tableView deleteSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationAutomatic];
            break;
    }
}

- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject atIndexPath:(NSIndexPath*)indexPath forChangeType:(NSFetchedResultsChangeType)type newIndexPath:(NSIndexPath*)newIndexPath {
    NSLog(@"%s", __PRETTY_FUNCTION__);
    UITableView* tableView = self.tableView;
    switch(type) {
        case NSFetchedResultsChangeInsert:
            [tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
            break;

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

        case NSFetchedResultsChangeUpdate:
    [(NewsItemCell*)[tableView cellForRowAtIndexPath:indexPath] updateWithNews:[self.fetchedResultsController objectAtIndexPath:indexPath]];
            break;

        case NSFetchedResultsChangeMove:
            [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
            [tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
            break;
    }
}

- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller {
    NSLog(@"%s", __PRETTY_FUNCTION__);
    [self.tableView endUpdates];
}

そして、これは私のセルレイアウトのコードです:

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
    return self.fetchedResultsController.sections.count;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    id<NSFetchedResultsSectionInfo> sectionInfo = [self.fetchedResultsController.sections objectAtIndex:section];
    return sectionInfo.numberOfObjects;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    News* model = [self.fetchedResultsController objectAtIndexPath:indexPath];

    NewsItemCell* cell = (NewsItemCell*)[tableView dequeueReusableCellWithIdentifier:NewsCellReuseIdentifier];
    [cell updateWithNews:model];
    cell.accessoryType = (model.content ? UITableViewCellAccessoryDisclosureIndicator : UITableViewCellAccessoryNone);
    return cell;
}

そして、セルのかなり基本的な更新:

- (void)updateWithNews:(News*)news {
    NSString* dateString = [[NSDateFormatter outputDateFormatter] stringFromDate:news.date];
    self.headlineLabel.text = (news.headline ? news.headline : NSLocalizedString(@"<NewsNoHeadlineReplacement>", nil));
    self.metaInfoLabel.text = [NSString stringWithFormat:NSLocalizedString(@"<NewsMetaInfoFormatDate>", nil), (dateString ? dateString : (NSLocalizedString(@"<NewsNoDateReplacement>", nil)))];

    self.readIndicatorView.hidden = (news.read != nil && [news.read compare:news.parsingDate] == NSOrderedDescending);
}

プレースホルダー文字列も表示されません。ラベルは完全に空です。画像のみが表示されます!

4

3 に答える 3

6

このコードに焦点を当てましょう:

 case NSFetchedResultsChangeUpdate:
        [(NewsItemCell*)[tableView cellForRowAtIndexPath:indexPath] updateWithNews:[self.fetchedResultsController objectAtIndexPath:indexPath]];
        break;

何が起こっているかを説明するには:

  1. tableViewで更新トランザクションを開きます
  2. 次に、tableViewにコマンドを発行して、デリゲート呼び出しに反応します
  3. ただし、更新の場合は、tableViewに関係のないコマンドを発行することで別の方法で行います。
  4. 次に、tableViewでトランザクションを閉じます

つまり、tableViewコマンドは変更を1つのトランザクションにバンドルする場合があります。セルを再レンダリングするための呼び出しは、次のトランザクションで終了するようです。したがって、上記のコードを次のように置き換えます。

case NSFetchedResultsChangeUpdate:
        [tableView reloadRowsAtIndexPaths: [NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationAutomatic ];
        break;
于 2012-10-23T19:19:18.557 に答える
4

私が最初にチェックすること:

  1. フェッチが別のスレッドで実行されていないことを確認してください
  2. フェッチが速いことを確認してください。遅すぎる場合は、それも原因である可能性があります。
于 2012-10-22T09:36:41.950 に答える
2

NSFetchedResultsControllerDelegateへの呼び出しはバックグラウンドスレッドで行われますか?それが問題かもしれません。テストするには、bg mocの変更をメインmocにマージし、bgmocの代わりにメインmocを観察します。NSManagedObjectContextのインスタンスは、1つのスレッドによってのみ使用されることになっています。

于 2012-10-22T22:20:22.123 に答える