Core Data崩溃求助:keypath count未在实体中找到异常排查
问题排查:CoreData分组统计时的NSInvalidArgumentException崩溃
NTSmartRegionGPS是继承自CoreData的NSManagedObject对象,以下retrievePercent方法用于实现数据库记录的分组统计并计算占比:
+ (NSArray *)retrievePercent{ NSArray *percentResult = [NSArray arrayWithObjects:@"", nil]; NSFetchRequest *fetchRequest = [NTSmartRegionGPS MR_createFetchRequest]; NSString *entityName = [NTSmartRegionGPS MR_entityName]; NSManagedObjectContext *context = [NSManagedObjectContext MR_context]; NSEntityDescription *entity = [NSEntityDescription entityForName:entityName inManagedObjectContext:context]; //查询结果展示对应的ssid值 NSAttributeDescription *compactKeyDesc = [entity.attributesByName objectForKey:@"compactKey"]; //统计ssid列数量 NSExpression *compactKeyExpn = [NSExpression expressionForKeyPath:@"compactKey"]; NSExpression *countExpn = [NSExpression expressionForFunction:@"count:" arguments:@[compactKeyExpn]]; NSExpressionDescription *countExpnDesc = [[NSExpressionDescription alloc] init]; countExpnDesc.name = @"count"; countExpnDesc.expression = countExpn; //TODO 使用NSInteger32AttributeType会导致百分比解析值异常,待排查原因 countExpnDesc.expressionResultType = NSStringAttributeType; //计算方式:count() * 100/countOfEntity //(实测发现除法结果会取整,为获取占比先乘以100) NSUInteger countOfEntity = [NTSmartRegionGPS MR_countOfEntities]; if (countOfEntity <= 0) { return percentResult; } NSExpression *multiplierValueExpn = [NSExpression expressionForConstantValue:@(100)]; NSExpression *multiplyExpn = [NSExpression expressionForFunction:@"multiply:by:" arguments:@[countExpn, multiplierValueExpn]]; NSExpression *sumValueExpn = [NSExpression expressionForConstantValue:@(countOfEntity)]; NSExpression *divideExpn = [NSExpression expressionForFunction:@"divide:by:" arguments:@[multiplyExpn, sumValueExpn]]; NSExpressionDescription *percentExpnDesc = [[NSExpressionDescription alloc] init]; percentExpnDesc.name = @"percent"; percentExpnDesc.expression = divideExpn; //TODO 使用NSInteger32AttributeType会导致百分比解析值异常,待排查原因 percentExpnDesc.expressionResultType= NSStringAttributeType; fetchRequest.returnsObjectsAsFaults = false; fetchRequest.resultType = NSDictionaryResultType; fetchRequest.propertiesToFetch = @[compactKeyDesc, countExpnDesc, percentExpnDesc]; fetchRequest.propertiesToGroupBy = @"compactKey"; //按count结果降序排序 NSSortDescriptor *sd = [NSSortDescriptor sortDescriptorWithKey:@"count" ascending:NO]; fetchRequest.sortDescriptors = @[sd]; @try { percentResult = [NTSmartRegionGPS MR_executeFetchRequest:fetchRequest]; } @catch (NSException *exception) { // 致命异常:NSInvalidArgumentException keypath count not found in entity NTSmartRegionGPS DDLogError(@"Fetch gps region percent fail, exception:%@", exception.reason); } return percentResult; }
本人在iPhone12真机测试时,数据库为空/单条数据/多条数据场景下均能正常输出占比结果,但用户侧出现崩溃,崩溃发生在percentResult = [NTSmartRegionGPS MR_executeFetchRequest:fetchRequest];代码行,崩溃信息为:Fatal Exception: 'NSInvalidArgumentException', reason: 'keypath count not found in entity '。以下是可能的崩溃原因及解决建议:
可能的崩溃原因
- MagicalRecord上下文不匹配:代码中通过
[NTSmartRegionGPS MR_createFetchRequest]创建请求,但获取实体描述时用的是[NSManagedObjectContext MR_context],两者可能属于不同的上下文(如主线程/后台线程上下文),导致CoreData无法识别查询中定义的count计算属性。 - CoreData版本兼容性问题:测试设备为iPhone12(iOS 14+),但用户设备可能运行更低版本的iOS系统。旧版CoreData对分组查询中使用计算属性作为排序条件的支持存在bug,无法正确解析
count这个别名。 - 排序描述符的key解析异常:使用
NSDictionaryResultType时,部分场景下CoreData不会将表达式描述的名称(count)识别为合法的排序keypath,导致找不到对应的字段。 - CoreData模型缓存不一致:用户设备上的CoreData模型可能存在缓存残留或迁移失败,导致实体结构与代码预期不符,无法识别计算字段。
解决建议
- 统一上下文:确保fetchRequest和实体描述使用同一个上下文,修改代码如下:
NSManagedObjectContext *context = [NSManagedObjectContext MR_context]; NSFetchRequest *fetchRequest = [NTSmartRegionGPS MR_createFetchRequestInContext:context];
- 内存中排序替代查询阶段排序:移除查询请求中的排序设置,获取结果后在内存中排序:
// 注释掉原有的排序设置 // NSSortDescriptor *sd = [NSSortDescriptor sortDescriptorWithKey:@"count" ascending:NO]; // fetchRequest.sortDescriptors = @[sd]; // 获取结果后再排序 @try { percentResult = [NTSmartRegionGPS MR_executeFetchRequest:fetchRequest]; NSSortDescriptor *sd = [NSSortDescriptor sortDescriptorWithKey:@"count" ascending:NO]; percentResult = [percentResult sortedArrayUsingDescriptors:@[sd]]; } @catch (NSException *exception) { DDLogError(@"Fetch gps region percent fail, exception:%@", exception.reason); }
- 使用表达式创建排序描述符:如果需要在查询阶段排序,直接用表达式创建排序描述符,避免keypath解析问题:
NSExpression *sortExpression = [NSExpression expressionForKeyPath:@"count"]; NSSortDescriptor *sd = [[NSSortDescriptor alloc] initWithExpression:sortExpression ascending:NO]; fetchRequest.sortDescriptors = @[sd];
- 清理模型缓存:指导用户重装应用,或在代码中完善CoreData模型迁移逻辑,确保实体结构正确同步。
内容的提问来源于stack exchange,提问作者Bingerz
相关产品推荐
相关产品推荐

