使用format和va_list / NSArray创建的NSPredicate失败但字符串成功

时间:2013-02-09 04:48:33

标签: objective-c nspredicate nsmanagedobject objective-c-category

我创建了NSManagedObject的类别,例如创建计数等。除了以下

之外,所有这些都可以找到
@interface NSManagedObject(ManagedObjectExtension) 
+ (id)findWithPredicate:(id)stringOrPredicate, ...;
@end

@implementation NSManagedObject(ManagedObjectUtilities)

+ (id)findWithPredicate:(id)stringOrPredicate, ... {
    NSFetchRequest *fetchRequest = [self allFetchRequest];
    if (stringOrPredicate) {
        NSPredicate *predicate;
        if ([stringOrPredicate isKindOfClass:[NSString class]]) {
            va_list variadicArguments;
            va_start(variadicArguments, stringOrPredicate);
            predicate = [NSPredicate predicateWithFormat:stringOrPredicate arguments:variadicArguments];
            va_end(variadicArguments);
        } else {
            predicate = (NSPredicate *)stringOrPredicate;
        }
        [fetchRequest setPredicate:predicate];
    }


    NSError *error;
    NSArray *results = [[self managedObjectContext] executeFetchRequest:fetchRequest error:&error];

    if (error) {
        NSLog(@"%@", [error description]);
    }

    if ([results count] == 0) {
        return nil;
    } else if ([results count] == 1) {
        return [results objectAtIndex:0];
    } else {
        return results;
    }
}

@end

这些是结果

NSString *email = [NSString stringWithString:someTextField.text];
NSLog(@"%@", [User findWithPredicate:@"email == "%@", email]);
==> (null)
NSLog(@"%@", [User findWithPredicate:[NSString stringWithFormat:@"email == "%@", email]]);
==> "<User: 0x1d827e10> ..."

基本上,只有当我发送字符串而不是格式化的字符串和参数时,此方法才有效。如果我打印在此方法中创建的谓词,则这些是结果

[User findWithPredicate:@"email == "%@", email];
==> email == "%@"
[User findWithPredicate:[NSString stringWithFormat:@"email == "%@", email]];
==> email == "tar.tw45@gmail.com"

你知道是什么原因引起的吗?欢迎任何评论或建议:)

1 个答案:

答案 0 :(得分:2)

我假设您忘记了问题代码中的引号(正如@kitschmaster在他的评论中所说)并且代码实际上是这样的:

NSString *email = @"tar.tw45@gmail.com";
// Case 1:
NSLog(@"%@", [User findWithPredicate:@"email == '%@'", email]);
// Case 2:
NSLog(@"%@", [User findWithPredicate:[NSString stringWithFormat:@"email == '%@'", email]]);

在案例(1) 中,您的实用程序方法会创建以下谓词

[NSPredicate predicateWithFormat:@"email == '%@'", email];

并且此谓词因引号而搜索逐字字符串 "%@"。如果删除引号:

NSLog(@"%@", [User findWithPredicate:@"email == %@", email]);

然后它正常工作。

如果是(2), 您的实用工具方法会创建谓词

[NSPredicate predicateWithFormat:@"email == 'tar.tw45@gmail.com'"];

因为它是使用已格式化的查询字符串调用的。这适用于这种特殊情况。但如果查询本身包含任何引号,它将失败。例如:

[User findWithPredicate:@"name == %@", @"a'b"]

正常工作,但

[User findWithPredicate:[NSString stringWithFormat:@"name == '%@'", @"a'b"]]

崩溃。 创建谓词时,通常应避免使用stringWithFormat

摘要: 如果省略格式字符串中的引号,则第一个版本可以正常工作。不应使用第二个版本。