2

「チェックリスト」項目を表示するための TableView を持つ UIViewController があります。この ViewController には、ユーザーが新しいチェックリスト項目を追加するための別の UIViewController をモーダルに表示するセグエをトリガーするボタンもあります。

すべてのチェックリスト項目は CoreData に保存されます。

新しい CoreData エンティティが作成され、SecondViewController. ユーザーはchecklist、 の却下をトリガーするボタンを押す前に、好きなだけ項目を追加できますSecondViewController。ここでSecondViewControllerは形式的に提示されているので、その活動は とはまったく関係がないと仮定しFirstUIViewControllerます。

FirstViewControllerを含むUITableViewには、再度NSFetchedResultsControllerCoreData でフェッチ要求を実行し、すべてのデータを にフィードする がありますUITableView。NSFetchedResultsController のデリゲートも this を指していFirstUIViewControllerます。

問題は、 の却下後、が新しいチェックリスト エンティティの挿入に気づき、UITableView 内に新しいエンティティを挿入しSecondViewControllerたように見えることです。ただし、奇妙なことに、この新しく挿入された行には適切な. ラベルに何も記載されていないブランクのみが表示されます。UITableViewUITableCellcell.textlabelUITableViewCell

以下は、私が設定する方法UITableViewCellです。

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *CellIdentifier = @"ChecklistCell";
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
    [self configureCell:cell atIndexPath:indexPath];
    return cell;
}

- (void)configureCell:(UITableViewCell *)cell atIndexPath:(NSIndexPath *)indexPath
{
    ChecklistItem *item = [self.fetch_controller objectAtIndexPath:indexPath];
    cell.textLabel.text = item.name;    
}

これが私がNSFetchedResultsControllerDelegateのために持っているものです

- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type newIndexPath:(NSIndexPath *)newIndexPath
{
    switch (type) {
        case NSFetchedResultsChangeInsert:
            NSLog(@"*** controllerDidChangeObject - NSFetchedResultsChangeInsert");
            [self.tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationFade];
            break;
    }
}

を強制する[self.tableView reloadData]と役立つようです。これは、このメソッドを呼び出すボタンを 1 つ追加したため、セルのラベルが更新され、それに応じて更新されたためです。

したがって、 の解任後に呼び出されることを期待して、これを試しましたSecondViewController。ただし、ログに記録されたためにメソッドが呼び出されReload Data!ますが、どういうわけか、tableView には新しく追加されたセルのラベルが正しく表示されません。

- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];
    [self performFetch];
    [self.tableView reloadData];
    NSLog(@"Reload Data!");
}

ここで何が間違っているのだろうか。self.tableViewの却下後、どういうわけかがリロードされませんSecondViewController。助言がありますか?

## 編集済み

OK、さらに奇妙なのは、私が[self.tableView reloadData]内部で試したこと- (void)viewDidAppear:(BOOL)animatedです。新しい tableViewCell はまだラベルを正しく表示しません。ただし、30 秒待つと、魔法のようにラベルが表示されます。これは、私の iPhone/iPhone シミュレーターが考えるのに時間がかかるということですか?

4

1 に答える 1

2

説明

コア データの保存には時間がかかります。データを保存してすぐにモーダル ビュー コントローラーを閉じると、performFetch関数で競合状態が発生します。viewWillAppearこれが、関数では機能しないのに、ボタンを押すと機能することがわかっている理由です。viewDidAppear で動作する場合もありますが、保証されていません。シミュレーターを使用しているかどうか、およびシステムがどれだけビジーかによって異なります。

具体的な提案

コア データからデータを取得しているため、 を使用NSFetchedResultsControllerして実装することをお勧めしますNSFetchedResultsControllerDelegate。これらは、coreData を UITableViewController にバインドするために特別に設計されました。変更をリッスンし、それらの変更に基づいて行をすぐに追加、削除、または更新します。

コードで更新

を適切に実装するNSFetchedResultsControllerDelegateには、次の Web サイトからコードをコピーするだけです

いくつかのヒント:

  1. の実装方法を少し変更する必要がありますcellForRowAtIndexPath。という新しいメソッドを作成しますconfigureCell。これはよく使われているパターンなので、Apple や他の場所の多くのサンプル コードで見つけることができます。
  2. 上記の Web サイトの「通常の使用」セクションからコードをコピーします。「ユーザー主導の更新」を実装する必要はありません。必ず設定してください

    self.fetchedResultsController.delegate = self;

  3. このコードが正しく機能しているかどうかを確認したい場合は、breakPoints または NSLogs をcontrollerWillChangeContentまたはに配置できますcontroller:didChangeObject

  4. 初めて performFetch を呼び出す必要はありません。このコードは、変更と更新を適切にリッスンします。
  5. いつも皆さんにアドバイスしているように、私は MagicalRecord が大好きなので、それを使用してください。

セルの構成

以下の configureCell:atIndexPath メソッドは、NSFetchedResultsController デリゲートによって呼び出されます。

- (void)configureCell:(UITableViewCell *)cell atIndexPath:(NSIndexPath *)indexPath {
    Product *product = [_fetchedResultsController objectAtIndexPath:indexPath];
    cell.textLabel.text = product.name;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {

    static NSString *CellIdentifier = @"Product Cell";
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (cell == nil) {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
    }

    [self configureCell:cell atIndexPath:indexPath];

    return cell;
}

デリゲートの実装コードはこちらを参照してください。オブジェクトが更新されたときに configureCell がどのように呼び出されるかを確認してください。

- (void)controllerWillChangeContent:(NSFetchedResultsController *)controller {
    [self.tableView beginUpdates];
}


- (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:UITableViewRowAnimationFade];
            break;

        case NSFetchedResultsChangeDelete:
            [self.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.tableView;

    switch(type) {

        case NSFetchedResultsChangeInsert:
            [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];
            [tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath]
                             withRowAnimation:UITableViewRowAnimationFade];
            break;
    }
}


- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller {
    [self.tableView endUpdates];
}
于 2013-02-18T18:38:30.563 に答える