poh*_*ohl 7 core-data objective-c nsfetchedresultscontroller nsfetchrequest ios
所以我不会埋没lede,我将打开我的核心问题:为什么我的NSFetchedResultsController的fetchedObjects数组通常是同类的,但在极少数情况下包含__NSCFString它应该包含的托管对象?
我有一个应用程序已经生产了很长一段时间.它的主要视图是一个表视图,其中包含由核心数据管理对象支持的视频列表.表视图控制器使用NSFetchedResultsController配置相当普通的NSFetchRequest:
NSFetchRequest *request = [[NSFetchRequest alloc] initWithEntityName:[ABCVideo entityName]];
NSString *sectionKeyPath = nil;
request.fetchBatchSize = 20;
NSSortDescriptor *sort = [[NSSortDescriptor alloc] initWithKey:ABCVideoAttributes.recordingDate ascending:NO];
sectionKeyPath = @"sectionIdentifier";
request.sortDescriptors = @[sort];
request.predicate = [NSPredicate predicateWithFormat:@"owner = %@ and %K = %@", person, ABCVideoAttributes.serverDeleted, @(NO)];
self.fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:request managedObjectContext:moc sectionNameKeyPath:sectionKeyPath cacheName:kABCMyVideosTableViewControllerCacheKey];
Run Code Online (Sandbox Code Playgroud)
由于这些视频可以上传到云端,因此该表格视图控制器会偶尔收到通知,以更新与当前正在上传的视频对应的表格视图单元格中的进度条.在这个回调中,我们得到NSFetchedResultsController的fetchedObjects数组用于查找与通知相对应的视频,以便正确的表格视图单元格可以更新其进度条.
这一切都有效.99.9%的时间,它每次都有效</RonBurgundy>.
但我注意到在我们的HockeyApp崩溃报告中,有一种罕见的,罕见的情况,当我的通知处理程序试图filteredArrayUsingPredicate从以下位置获取时,我收到SIGABRT fetchedObjects:
*** Terminating app due to uncaught exception 'NSUnknownKeyException', reason: '[<__NSCFString 0x136f24480> valueForUndefinedKey:]: this class is not key value coding-compliant for the key guid.'
最近我设法找到一个案例,我偶尔可以重现这个崩溃,经过大量的实验,我发现fetchedObjects数组有时包含的东西不是ABCVideo:相反,数组中的一个插槽被一个__NSCFString实例占用.这非常令人惊讶,因为它NSFetchRequestResultType是NSManagedObjectResultType,而字符串不是托管对象.
所以我想知道:这是一个核心数据错误吗?或者我的数组是否包含一个指针,该指针以前指向一个ABCVideo已解除分配的实例,并且该堆上的位置随后被__NSCFString实例占用?如果是后者,那怎么会发生这种情况呢?我正在使用ARC,所以很难理解其中一个视频是如何被取消分配的.
有一个内存管理错误中-[NSFetchedResultsController fetchedObjects]有NSFastEnumeration。对象0x136f24480是ABCVideo,但已释放。该内存用于存储__NSCFString。将消息发送到错误的对象EXC_BAD_ACCESS和SIGABRT是常见的结果。
此错误也存在于我的应用程序中,但是即使一次也无法重现。如果您愿意分享一个可以重现该问题的示例项目,我们可以一起解决。
有多种解决方法。关键是要避免NSFastEnumeration上fetchedObjects
// 1
NSArray *fetchedObjects = controller.fetchedObjects
for (int i = 0; i < fetchedObjects.count; ++i) {
NSManagedObject *object = fetchedObjects[i];
}
// 2
NSArray <id<NSFetchedResultsSectionInfo>> *sections = controller.sections;
for (int s = 0; s < sections.count; ++s) {
id<NSFetchedResultsSectionInfo> section = sections[s];
for (int i = 0; i < [section numberOfObjects]; ++i) {
NSManagedObject *object = [controller objectAtIndexPath:[NSIndexPath indexPathForItem:i inSection:s]];
}
}
// 3 Fetch from NSManagedContextDirectly
Run Code Online (Sandbox Code Playgroud)
如果不幸的是,有人在读这篇文章时使用的是Swift,则即使调用也会导致崩溃,fetchedObjects因为Swift转换NSArray为Arrayusing NSFastEnumeration。
| 归档时间: |
|
| 查看次数: |
736 次 |
| 最近记录: |