归档解码NSPredicate后出现‘该谓词已禁用评估’错误求助
问题原因与解决方法:归档解码后的NSPredicate抛出"This predicate has evaluation disabled"异常
核心原因
安全归档解码后的NSPredicate默认被禁用了内存中的谓词求值功能,这是苹果的安全防护机制:
- 当使用
requiringSecureCoding:YES归档,并通过unarchivedObjectOfClass:fromData:解码时,系统会自动限制该谓词的使用场景——仅允许在Core Data的NSFetchRequest中使用(因为Core Data会将谓词转换为SQL语句执行,不触发内存中的求值逻辑); - 直接在内存集合(如
NSArray的filteredArrayUsingPredicate:)或NSArrayController中使用时,会触发谓词的内存求值逻辑,此时受限状态的谓词就会抛出异常。
关键验证点说明
isEqualTo:返回YES:该方法仅比较谓词的逻辑结构、格式参数,不会检查allowsEvaluation的启用状态,因此两个谓词会被判定为相等;- 可用于
NSFetchRequest:Core Data的查询路径不依赖谓词的内存求值能力,而是将谓词转换为SQL,因此不受安全限制影响。
解决方法
方法1:启用解码后谓词的求值能力(仅适用于可信数据源)
如果归档数据来自App内部生成的可信来源(比如自己的用户默认设置),可以手动开启谓词的求值权限:
NSError *error = nil; NSPredicate *decodedPredicate = [NSKeyedUnarchiver unarchivedObjectOfClass:NSPredicate.class fromData:filterPredicateData error:&error]; if (decodedPredicate && !decodedPredicate.allowsEvaluation) { [decodedPredicate setAllowsEvaluation:YES]; }
注意:如果数据来自不可信外部来源,不要使用此方法,避免潜在的代码注入风险。
方法2:归档谓词格式字符串,解码时重新创建(更安全)
替代归档NSPredicate对象,改为归档它的predicateFormat字符串,解码时重新生成谓词:
// 归档到用户默认设置 NSString *predicateFormat = filterPredicate.predicateFormat; [[NSUserDefaults standardUserDefaults] setObject:predicateFormat forKey:@"SavedFilterPredicate"]; // 从用户默认设置恢复 NSString *savedFormat = [[NSUserDefaults standardUserDefaults] stringForKey:@"SavedFilterPredicate"]; NSPredicate *restoredPredicate = [NSPredicate predicateWithFormat:savedFormat];
这种方法完全避开安全限制,因为新创建的谓词默认允许内存求值,同时也更轻量化。
内容的提问来源于stack exchange,提问作者jeanlain
相关产品推荐
相关产品推荐

