核心数据预取和 KVO 合规性
Posted
技术标签:
【中文标题】核心数据预取和 KVO 合规性【英文标题】:Core Data pre-fetching and KVO compliance 【发布时间】:2013-01-01 15:56:51 【问题描述】:如果我尝试在 Core Data 中预取相关实体,则会引发 KVO 异常。这对我来说没有任何意义,我似乎无法在简化项目中复制这种行为。我的目标是 10.8 并使用 ARC。
我的数据为音乐库建模,我有三个感兴趣的实体:Track
、Artist
和 Album
。曲目有一个艺术家和一个专辑,而专辑有一个艺术家。我的 Album
和 Artist
对象的名称是唯一的(商店中只有一位具有给定名称的艺术家)。
我想显示包含以下字段的曲目列表:标题、艺术家姓名、专辑标题。这很容易通过使用Track
实体的 NSArrayController 和 NSTableView 中的绑定来完成。
但是,由于我知道我将使用艺术家和专辑关系,因此我想在加载曲目时预取它们。我创建了一个带有自定义 performFetch: 方法的 NSArrayController 子类,如下所示:
- (BOOL) fetchWithRequest:(NSFetchRequest *)fetchRequest merge:(BOOL)merge error:(NSError *__autoreleasing *)error
NSEntityDescription *entityDescription = [Track entityInManagedObjectContext:[self managedObjectContext]];
fetchRequest = [[NSFetchRequest alloc] init];
[fetchRequest setEntity:entityDescription];
[fetchRequest setRelationshipKeyPathsForPrefetching:@[@"album", @"artist"]];
return [super fetchWithRequest:fetchRequest merge:merge error:error];
我将 IB 中的 NSArrayController 的类设置为我的子类,我预计 UI 滞后会消失(每次滚动都会触发故障)。但是,抛出异常:
2013-01-01 10:48:06.965 XXX[10593:303] 无法更新 关键路径“artist.name”的观察者 from ,很可能是因为键的值 “艺术家”在没有适当的 KVO 通知的情况下发生了变化 发送。检查 Track 类的 KVO 兼容性。
在自定义 NSArrayController
子类之前,一切正常。通过简单地在我的NSArrayController
子类中注释掉setRelationshipKeyPathsForPrefetching
行,一切都会再次起作用。我无法确定预取和 KVO 之间的联系是什么。以前有没有 Core Data 专家见过这样的事情?
【问题讨论】:
你在某处打电话给willChangeValueForKey:
和didChangeValueForKey:
吗?
不,我不进行任何手动 KVC 调用。我在 NSManagedObject
子类中使用 Core Data 的综合 setter/getter。
这似乎是 Apple 的错误,NSFetchedResultsController 也会发生。
【参考方案1】:
我遇到了基本相同的问题,这是我在解决它时学到的:
似乎 NSArrayController 在所有情况下都不能很好地与setRelationshipKeyPathsForPrefetching:
配合使用。我在子上下文中执行预取请求,这最终破坏了父上下文中 NSArrayController
的 KVC,我认为这是意外行为。无论如何,我修复它的方法是使用"old" style (10.4) prefetching,它看起来像......
NSFetchRequest *trackReq = [[NSFetchRequest alloc] initWithEntityName:@"Track"];
NSArray *fetchedTracks = [context executeFetchRequest:trackReq error:&error];
NSFetchRequest *batchFaultReq = [[NSFetchRequest alloc] initWithEntityName:@"Artist"];
[batchFaultReq setPredicate:[NSPredicate predicateWithFormat:@"SELF.tracks in %@", fetchedTracks];
NSArray *faultedItems = [context executeFetchRequest:batchFaultReq error:&error];
// do something with fetchedTracks
...如何将其插入您的 NSArrayController
子类是另一回事 - 我不清楚如何在 fetchWithRequest:
覆盖中使用此方法,因为您需要获取的结果才能执行批处理故障要求。顺便说一句,您已经尝试过延迟获取标志?
【讨论】:
我最终覆盖了-defaultFetchRequest
来执行与我上面概述的基本相同的获取请求并且一切正常。以上是关于核心数据预取和 KVO 合规性的主要内容,如果未能解决你的问题,请参考以下文章