【发布时间】:2013-10-18 14:18:36
【问题描述】:
我必须将数据从以前的应用版本迁移到新版本。这也会影响用户保存的一些谓词(NSPredicate 实例),这意味着我必须以编程方式更改它们。
目前我尝试解析使用[NSPredicate predicateFormat] 获得的字符串并手动更改一些表达式。例如oldKeyPath == "something" 到newKeyPath == "something"。但这感觉像是一种 hack,我很好奇是否有更好的方法?
我阅读了 Apple 关于使用 NSPredicate 和 NSExpression 进行编程的文档。有很多方法可以从NSExpressions 组合NSPredicate 对象。我希望找到从NSPredicate 获取NSExpression 对象的相反方法。我错过了什么吗?
感谢您的任何提示。
解决方案
感谢 Martin R,我能够在 NSPredicate 上创建一个类别,允许我对表达式进行修改。
@implementation NSPredicate (ExtractComparisions)
- (NSPredicate *)predicateByChangingComparisionsWithBlock:(NSPredicate *(^)(NSComparisonPredicate *))block {
if ([self isKindOfClass: [NSCompoundPredicate class]]) {
NSCompoundPredicate *compPred = (NSCompoundPredicate *)self;
NSMutableArray *predicates = [NSMutableArray array];
for (NSPredicate *predicate in [compPred subpredicates]) {
NSPredicate *newPredicate = [predicate predicateByChangingComparisionsWithBlock: block];
if (newPredicate != nil)
[predicates addObject: newPredicate];
}
return [[[NSCompoundPredicate alloc] initWithType: compPred.compoundPredicateType
subpredicates: predicates] autorelease];
} if ([self isKindOfClass: [NSComparisonPredicate class]]) {
return block((NSComparisonPredicate *)self);
}
return self;
}
@end
这是一个示例代码,说明如何使用它
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
NSPredicate *predicate = [NSPredicate predicateWithFormat: @"key.path like %@ and count > 17", @"Hello"];
NSPredicate *newPredicate = [predicate predicateByChangingComparisionsWithBlock:
^NSPredicate *(NSComparisonPredicate *cp) {
NSExpression *left = [cp leftExpression];
NSExpression *right = [cp rightExpression];
if ([[cp leftExpression] expressionType] == NSKeyPathExpressionType) {
NSString *keyPath = [[cp leftExpression] keyPath];
if ([keyPath isEqualToString: @"key.path"])
left = [NSExpression expressionForKeyPath: @"key.new.path"];
return [NSComparisonPredicate predicateWithLeftExpression: left
rightExpression: right
modifier: cp.comparisonPredicateModifier
type: cp.predicateOperatorType
options:cp.options];
}
return cp;
}];
NSLog(@"Before: %@", predicate);
NSLog(@"After: %@", newPredicate);
}
【问题讨论】:
-
不错!请注意,您还可以为每个子类 NSCompoundPredicate 和 NSComparisonPredicate 实现不同的类别方法。这使得 isKindOfClass 检查和强制转换过时(并且看起来很复杂:-)
-
是的,我考虑过这一点,但我意识到我仍然必须调用超类 NSPredicate 上的方法,因为我不知道类的确切类型,或者我必须先转换它。所以我做出了妥协并“隐藏”了超类中的演员表。 NSPredicate 看起来不像是我们必须通过子类扩展的类。但我仍然同意更复杂的方式。也许我稍后会在我的代码中更改它。 ——
标签: cocoa migration nspredicate nsexpression