【问题标题】:NSFetchedResultsController complex fetch request and modelNSFetchedResultsController 复杂的获取请求和模型
【发布时间】:2016-09-24 08:27:35
【问题描述】:

我正在尝试针对这种情况设计我的 CoreData 模型:

我们有 Song 对象,它与一些 List 有一对多关系。

每个List 都有name 属性并且还与Song 有一对多关系

需要这些多对多关系,因为一个Song 可以同时出现在每个List 中。

我需要使用NSFetchedResultsController 以某种方式获取按这些标题(List 的名称)分组的Songs 列表(因为用户可能有 10,000 首歌曲,我不想将其存储在 NSArray 的某个位置)。

当我尝试将 sectionNameKeyPath: 设置为某个值时,例如@"List.name" 我有一个错误“不允许多对多关系”,当然这是有道理的。

所以我需要帮助如何设计我的模型,以便能够拥有 Songs 和一些 Lists,如“历史”/“下一场比赛”等,并能够使用 @987654337 获取所有数据@。

任何帮助表示赞赏。如果我的解释不清楚,请询问更多信息。

我的部分代码:

- (void)initFetch {
    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] initWithEntityName:@"Song"];

    [fetchRequest setSortDescriptors:@[[NSSortDescriptor sortDescriptorWithKey:@"index" ascending:YES]]];
    fetchRequest.predicate = [NSPredicate predicateWithFormat:@"ANY list.@count != 0"];
    fetchRequest.fetchBatchSize = 20;

    self.fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:self.context sectionNameKeyPath:@"name" cacheName:nil];
    [self.fetchedResultsController setDelegate:self];

    NSError *error = nil;
    [self.fetchedResultsController performFetch:&error];

    if (error) {
        NSLog(@"Unable to perform fetch.");
        NSLog(@"%@, %@", error, error.localizedDescription);
    }
}

【问题讨论】:

    标签: ios objective-c core-data nsfetchedresultscontroller


    【解决方案1】:

    使用 FRC 可以很好地向您的用户显示数据,但在使用它时,它可以决定您的模型需要如何构建,而不是您可能认为模型实体和关系应该如何构建。在您的情况下,您似乎希望查看数据库中歌曲的实际States 列表,而不是歌曲列表。每个状态实例都与歌曲具有一对一的关系,并且状态在您的列表中可能具有一对多的关系,例如。链接到 History 列表、playNext 列表、currentPlaying“列表”(在最后一种情况下只有一个实例)。通过将您的 FRC 实体设置为此 State 实体和链接到状态所在列表的部分键路径,您可以实现上述要求,而无需操作 indexPaths 或使用多个 FRC。拥有这个单独的实体还允许您稍后添加其他属性,例如上次播放的日期或播放次数的汇总。所有这些都可以在 state 实体上完成,而不是在 Song 实体本身上完成。

    【讨论】:

    • 这是对我的答案中一个选项的详细描述,它解释得很好,但我不会重用状态实例,因为这会使管理和使用更加困难(一对一关系意味着获取列表名称很简单,并且在不再需要状态时很容易删除状态 - 可以通过删除规则完成)
    • 我同意我并不是要重用状态实例。我的意思是每个状态实例都会链接到一个列表,然后在发生变化时创建一个新的状态实例。我想我没有解释清楚。我也刚刚再次阅读了您的答案,并注意到您提到的最后一个选项“中间”对象与我在这里提出的解决方案类型相同。
    【解决方案2】:

    您不需要使用 FRC 来防止过多的数据加载,它不是这样做的。 FRC 的强大之处在于它通过观察上下文来检测变化。当您尝试跨关系导航时,这种能力也不能很好地发挥作用,因此在这种情况下您可能也不会从使用 FRC 中获益。

    限制您的数据使用的因素是在您不再需要托管对象时(在某些情况下是手动操作,但系统会在需要时自行执行此操作)和批处理获取请求时对其进行重新故障处理。当您在获取请求上设置批量大小时,返回的NSArray 将处理一次仅将数据页加载到内存中。 FRC 从中受益,但无法控制它 - 如果您忘记添加批次,FRC 将不会为您执行此操作!

    因此,您可以设置一个具有多个阵列的系统,每个部分 1 个阵列,并自行管理所有内容。或者,您可以使用多个 FRC,每个部分 1 个,并操纵索引路径,以便将所有内容挂在一起。

    或者,您可以通过在List 中添加代表Song 成员资格的中间对象来更改您的数据模型,因为这会破坏多对多关系并让您在更早的时候获得可导航的关系和排序描述符。在这种情况下,新实体将是您为 FRC 获取的实体。请注意上面提到的有关跨关系更改跟踪的问题,请注意您更改的内容以及更改方式...

    【讨论】:

    • 感谢您的评论,但我不同意您关于 FRC 无助于减少内存量的说法。例如,我的应用程序现在可以有一个包含超过 20000 首歌曲的播放列表,当我获取所有这些记录时,应用程序就会崩溃。我不喜欢手动管理所有这些东西的想法,我不知道如何做到这一点:) 另外,@Brad's answer 声明 FRC 在我的情况下非常有用。
    • Brads 的回答是完全正确的,它也和我说的一样,关于 fetch batch size 是内存管理的关键。不过,他不涵盖人际关系,这就是我所涵盖的内容以及您遇到的问题。我建议更改您的数据模型...
    • 我不明白,为什么将 n:m 分解为中间对象会有所帮助。这不是 n:m 关系的实现问题。但是,我也建议使用多个 FRC。
    • @AminNegm-Awad 因为它可以提供轻松查询谓词、排序和部分中的关系的能力。多对多增加了复杂性。多个 FRC 都可以,你只需要篡改索引路径...
    猜你喜欢
    • 2015-09-16
    • 2011-02-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-02-03
    • 1970-01-01
    相关资源
    最近更新 更多