返回

CoreData请求(Fetch Request)断言(NSPredicate)使用误区

IOS

面面俱到?

    NSPredicate * predicate = [NSPredicate predicateWithBlock:^BOOL(User *evaluatedObject, NSDictionary *bindings) {
        return evaluatedObject.status.integerValue == UserStatusActive;
    }];

    NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"User"];
    request.predicate = predicate;

这段代码中,谓词中的evaluatedObject.status.integerValue == UserStatusActive这样的判断是错误的。statusNSNumber类型,而UserStatusActive却是NSInteger。显然这是一个隐式类型转换,这在CoreData中不是一个好主意。

正确姿势:

    NSPredicate * predicate = [NSPredicate predicateWithBlock:^BOOL(User *evaluatedObject, NSDictionary *bindings) {
        return evaluatedObject.status == [NSNumber numberWithInteger:UserStatusActive];
    }];

nil is nil

    NSPredicate *predicate = [NSPredicate predicateWithBlock:^BOOL(User *evaluatedObject, NSDictionary *bindings) {
        return evaluatedObject.name.length;
    }];

length属性返回NSUInteger类型,这表示不可能为nil 。但谓词会返回NO,而不是你期望的YES。这是因为nil对象没有length属性,导致谓词条件永远不会满足。

正确姿势:

    NSPredicate *predicate = [NSPredicate predicateWithBlock:^BOOL(User *evaluatedObject, NSDictionary *bindings) {
        return evaluatedObject.name != nil && evaluatedObject.name.length;
    }];

BOOL类型比较

    NSPredicate *predicate = [NSPredicate predicateWithBlock:^BOOL(User *evaluatedObject, NSDictionary *bindings) {
        return evaluatedObject.active.boolValue == YES;
    }];

active属性类型是BOOL,而YES却是NSInteger。编译器不会通过上面的代码。

正确姿势:

    NSPredicate *predicate = [NSPredicate predicateWithBlock:^BOOL(User *evaluatedObject, NSDictionary *bindings) {
        return evaluatedObject.active.boolValue;
    }];

类型转换

    NSPredicate *predicate = [NSPredicate predicateWithBlock:^BOOL(User *evaluatedObject, NSDictionary *bindings) {
        return [evaluatedObject.status integerValue] < 5;
    }];

同上,statusNSNumber类型,而[evaluatedObject.status integerValue]却是NSInteger,也是一个隐式类型转换。

正确姿势:

    NSPredicate *predicate = [NSPredicate predicateWithBlock:^BOOL(User *evaluatedObject, NSDictionary *bindings) {
        return evaluatedObject.status.integerValue < 5;
    }];

使用KVC

    NSPredicate * predicate = [NSPredicate predicateWithBlock:^BOOL(User *evaluatedObject, NSDictionary *bindings) {
        return evaluatedObject.status.integerValue == [[NSUserDefaults standardUserDefaults] integerForKey:@"UserStatusActive"];
    }];

看起来似乎没有什么问题,但实际上会出乎意料。这是因为KVC会对UserStatusActive键进行类型转换,返回一个NSNumber对象。

正确姿势:

    NSInteger status = [[NSUserDefaults standardUserDefaults] integerForKey:@"UserStatusActive"];
    NSPredicate * predicate = [NSPredicate predicateWithBlock:^BOOL(User *evaluatedObject, NSDictionary *bindings) {
        return evaluatedObject.status.integerValue == status;
    }];

总结

使用断言(NSPredicate)时需要注意以下几点:

  • 避免隐式类型转换
  • 确保nil对象不会导致谓词失败
  • BOOL类型的比较直接使用boolValue属性
  • 类型转换时明确指定转换类型
  • 使用KVC时注意类型转换

遵循这些准则,可以避免使用断言(NSPredicate)时的常见错误,并确保您的CoreData查询按预期工作。