28

私がやりたいことはとても簡単です。UITableViewControllerで、複数のNSFetchedResultControllers(データモデルに複数のエンティティがあります)からデータをロードし、それぞれのデータをテーブルビューの異なるセクションに配置します。したがって、たとえば、最初のNSFetchedResultControllerからフェッチされたすべてのアイテムはUITableViewのセクション0に移動し、他のアイテムからフェッチされたアイテムはセクション1に移動します。

Core Dataテンプレートプロジェクトは、これを行う方法を示していません。すべて(主にインデックスパス)はセクションを考慮せずにコーディングされ(デフォルトのテンプレートにはセクションがありません)、すべてが単一のNSFetchedResultControllerから取得されます。これを行うことを示すサンプルプロジェクトまたはドキュメントはありますか?

ありがとう

4

3 に答える 3

26

しばらくの間、ヘッダーに次のようなものがあると仮定します(以下のコードは少しずさんなものになります、お詫びします)。

NSFetchedResultsController *fetchedResultsController1; // first section data
NSFetchedResultsController *fetchedResultsController2; // second section data

2つのセクションが必要であることをテーブルに知らせます。

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
    return 2; // you wanted 2 sections
}

セクションのタイトルを付けます。

- (NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView {
    return [NSArray arrayWithObjects:@"First section title", @"Second section title", nil];
}

セクションごとに行がいくつあるかをテーブルに知らせます。

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    if (section == 0) {
        return [[fetchedResultsController1 fetchedObjects] count];
    } else if (section == 1) {
        return [[fetchedResultsController2 fetchedObjects] count];
    }

    return 0;
}

セルを構築します。

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    ... // table cell dequeue or creation, boilerplate stuff

    // customize the cell
    if (indexPath.section == 0) {
        // get the managed object from fetchedResultsController1
        // customize the cell based on the data
    } else if (indexPath.section == 1) {
        // get the managed object from fetchedResultsController2
        // customize the cell based on the data
    }

    return cell;
}
于 2010-02-22T09:14:32.987 に答える
9

複数のフェッチコントローラー(および場合によっては複数のエンティティ)は間違ったアプローチです。正しい解決策は、sectionNameKeyPathパラメータを使用しNSFetchedResultControllerて結果を複数のセクションにグループ化することです。エンティティについて別の考え方をする場合は、実際には同じエンティティである可能性があり、代わりにitemType、セクション化できるプロパティを使用できます(また、それも並べ替える必要があります)。たとえば、HopsとGrainsのエンティティがある場合、それらをIngredientに変更し、int_16プロパティを設定して、値をingredientType格納するための列挙型をコードに含めることができます。結局のところ、成分は単なる名前と重さであり、これらの両方が共有しています。hopType = 0grainType = 1

sortOrderただし、エンティティに実際に個別のプロパティセットがある場合、正しい解決策は、セクションに使用できるプロパティを持つ親抽象エンティティを作成することsectionIDですtype。次に、フェッチコントローラを作成し、抽象親エンティティをフェッチすると、実際にはすべてのサブエンティティを含む結果が得られます。たとえば、メモアプリでは、NoteContainer子エンティティAccountとを含む抽象的な親エンティティがありFolderます。これにより、単一のフェッチコントローラーで、セクションの最初のセルにアカウントを表示し、次のセルにすべてのフォルダーを配置できます。たとえば、すべてのiCloud Notes(実際にはアカウント)、Notes(デフォルトのフォルダ)、すべてのカスタムフォルダ、ごみ箱フォルダの順になります。彼らは使用しますsortOrderプロパティとデフォルトフォルダは1、カスタムフォルダはすべて2、そしてゴミ箱は3です。次に、これを並べ替え記述子として追加することで、セルを希望の順序で表示できます。2つのエンティティが異なるセクションに混在しているため、要件とは少し異なりますが、異なるソートプロパティだけで使用できます。

物語の教訓は、フレームワークと戦うのではなく、それを受け入れることです:-)

于 2017-10-18T13:55:00.183 に答える
5

2つのNSFetchedResultsControllersを使用してGiaoのソリューションを拡張する-NSFetchedResultsControllerが2つのセクションを認識していないことを覚えておく必要があり、返されるNSIndexPathesは常に最初のセクションになります。

したがって、セル構成でオブジェクトを取得する場合:

- (UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cell"];
    if (!cell) {
        [tableView registerNib:[UINib nibWithNibName:@"cell" bundle:nil] forCellReuseIdentifier:@"cell"];
        cell = [tableView dequeueReusableCellWithIdentifier:@"cell"];
    }
    [self configureCell:cell atIndexPath:indexPath];
    return cell;
}

-(void)configureCell:(UITableViewCell*)cell atIndexPath:(NSIndexPath *)indexPath {
    if (indexPath.section == 0) {
        NSManagedObject *object = [self.fetchedResults1 objectAtIndexPath:[NSIndexPath indexPathForRow:indexPath.row inSection:0]];
        //use object to configure cell
    } else {
        NSManagedObject *object = [self.fetchedResults2 objectAtIndexPath:[NSIndexPath indexPathForRow:indexPath.row inSection:0]];
        //use object to configure cell
    }
}

NSFetchedResultsControllerがいくつかの変更に気付いたときにセルを更新します。

- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type newIndexPath:(NSIndexPath *)newIndexPath {
    NSIndexPath *customIndexPath = [NSIndexPath indexPathForRow:indexPath.row inSection:(controller == self.fetchedResultsController1)?0:1];
    NSIndexPath *customNewIndexPath = [NSIndexPath indexPathForRow:newIndexPath.row inSection:(controller == self.fetchedResultsController2)?0:1];
    switch(type) {
        case NSFetchedResultsChangeInsert:
            [tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:customNewIndexPath] withRowAnimation:UITableViewRowAnimationFade];
            break;
        case NSFetchedResultsChangeDelete:
            [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:customIndexPath] withRowAnimation:UITableViewRowAnimationFade];
            break;
        case NSFetchedResultsChangeUpdate:
            [self configureCell:[tableView cellForRowAtIndexPath:indexPath] atIndexPath:indexPath];
            break;
        case NSFetchedResultsChangeMove:
            [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:customIndexPath] withRowAnimation:UITableViewRowAnimationFade];
            [tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:customNewIndexPath] withRowAnimation:UITableViewRowAnimationFade];
            break;
    }
}
于 2017-03-07T11:41:42.327 に答える