解析和更改NSPredicate [英] Parsing and changing NSPredicate

查看:163
本文介绍了解析和更改NSPredicate的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我必须将资料从先前的应用程式版本迁移到新版本。这也影响了用户保存的一些谓词( NSPredicate 实例),这意味着我必须以编程方式更改它们。



目前,我尝试解析使用 [NSPredicate predicateFormat] 获得的字符串,并手动更改一些表达式。例如 oldKeyPath ==something newKeyPath ==something。但是它感觉像一个黑客,我很好奇,如果有一个更好的方法?



我读了关于使用NSPredicate和NSExpression编程的Apple的文档。有很多方法从 NSExpressions 中组成 NSPredicate 对象。我希望找到从 NSPredicate 中获取 NSExpression 对象的相反方法。

/ p>

感谢Martin RI能够在 NSPredicate 上创建一个类别,允许我对表达式进行修改。 p>

  @implementation NSPredicate(ExtractComparisions)

- (NSPredicate *)predicateByChangingComparisionsWithBlock:(NSPredicate * NSCompoundPredicate *))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 。因此,您可以检查谓词的实际
类,将其转换为该类的对象,然后
检查其属性。如果必要,用子谓词或
表达式重复此过程。



以下是一个简单复合谓词如何可能的例子
解剖这样。这不是检查所有情况的一般解决方案,
,但可能指向正确的方向。

  NSPredicate * p0 = [NSPredicate predicateWithFormat:@foo ='bar'AND count> 17 

if([p0 isKindOfClass:[NSCompoundPredicate class]]){
NSCompoundPredicate * p0a =(NSCompoundPredicate *)p0;
NSCompoundPredicateType type0 = p0a.compoundPredicateType; // NSAndPredicateType
NSPredicate * p1 = p0a.subpredicates [0]; // foo ='bar'
NSPredicate * p2 = p0a.subpredicates [1]; // count> 17
if([p1 isKindOfClass:[NSComparisonPredicate class]]){
NSComparisonPredicate * p1a =(NSComparisonPredicate *)p1;
NSPredicateOperatorType type1 = p1a.predicateOperatorType; // NSEqualToPredicateOperatorType
NSExpression * e3 = p1a.leftExpression; // foo,NSKeyPathExpression
NSExpression * e4 = p1a.rightExpression; //bar,NSConstantValueExpression
}
if([p2 isKindOfClass:[NSComparisonPredicate class]]){
NSComparisonPredicate * p2a =(NSComparisonPredicate *)p2;
NSPredicateOperatorType type2 = p2a.predicateOperatorType; // NSGreaterThanPredicateOperatorType
NSExpression * e5 = p2a.leftExpression; // count,NSKeyPathExpression
NSExpression * e6 = p2a.rightExpression; // 17,NSConstantValueExpression
}
}


I have to migrate data from a previous app version to a new version. This also affects some predicates (NSPredicate instances) that were saved by users, which means that I have to change them programmatically.

Currently I try to parse the string I get with [NSPredicate predicateFormat] and change some expressions manually. For instance oldKeyPath == "something" to newKeyPath == "something". But it feels like a hack and I'm curious if there is a better way?

I read Apple's documentations about programming with NSPredicate and NSExpression. There are plenty methods to compose NSPredicate objects from NSExpressions. I was hoping to find the reverse way to get NSExpression objects from a NSPredicate. Am I missing something?

Thank you for any hint.

Solution

Thanks to Martin R I was able to make a category on NSPredicate that allows me to inject modifications to expressions.

@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

Here is a sample code on how to use it

- (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);
}

解决方案

(This is just an idea.) Every predicate is an instance of a subclass like NSCompoundPredicate or NSComparisonPredicate. So you can check the actual class of the predicate, cast it to an object of that class and then inspect its properties. If necessary, repeat the process with sub-predicates or expressions.

The following is just an example how a simple compound predicate could be "dissected" that way. It is not the general solution that checks for all cases, but may point you into the right direction.

NSPredicate *p0 = [NSPredicate predicateWithFormat:@"foo = 'bar' AND count > 17"];

if ([p0 isKindOfClass:[NSCompoundPredicate class]]) {
    NSCompoundPredicate *p0a = (NSCompoundPredicate *)p0;
    NSCompoundPredicateType type0 = p0a.compoundPredicateType;  // NSAndPredicateType
    NSPredicate *p1 = p0a.subpredicates[0];                     // foo = 'bar'
    NSPredicate *p2 = p0a.subpredicates[1];                     // count > 17
    if ([p1 isKindOfClass:[NSComparisonPredicate class]]) {
        NSComparisonPredicate *p1a = (NSComparisonPredicate *)p1;
        NSPredicateOperatorType type1 = p1a.predicateOperatorType;  // NSEqualToPredicateOperatorType
        NSExpression *e3 = p1a.leftExpression;                  // foo, NSKeyPathExpression
        NSExpression *e4 = p1a.rightExpression;                 // "bar", NSConstantValueExpression
    }
    if ([p2 isKindOfClass:[NSComparisonPredicate class]]) {
        NSComparisonPredicate *p2a = (NSComparisonPredicate *)p2;
        NSPredicateOperatorType type2 = p2a.predicateOperatorType;  // NSGreaterThanPredicateOperatorType
        NSExpression *e5 = p2a.leftExpression;                  // count, NSKeyPathExpression
        NSExpression *e6 = p2a.rightExpression;                 // 17, NSConstantValueExpression
    }
}

这篇关于解析和更改NSPredicate的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆