美文网首页
KVC之添加验证方法

KVC之添加验证方法

作者: 哆啦_ | 来源:发表于2018-05-11 23:16 被阅读20次

    KVC协议定义了通过keykey path来验证属性的方法。这些方法的默认实现反过来依赖与你定义的遵循访问器方法命名规则的方法。具体来说,你为任何一个你想要验证的名为key的属性提供一个validate<Key>:error:方法。 默认实现是通过键编码的validateValue:forKey:error:消息来搜索的。

    如果未提供属性的验证方法,该协议的默认实现假定该属性的验证成功,而不管该值如何。 这意味着你选择逐个属性的验证。

    通常仅在Objective-C中使用此处所述的验证。 在Swift中,属性验证通过依赖于编译器和强类型检查的支持来处理,同时使用内置的willSet和didSet属性观察器来测试任何运行时API.感兴趣的同学可以查看Property Observers In Swift

    验证方法的实现

    当为一个属性提供验证方法时,该方法由两个参数:要验证的value对象和用于返回错误信息的NSError。因此,验证方法可以采取以下三种操作之一:

    • value对象有效时,返回YES,(不更改value或者error)
    • value对象无效时,并且你不能或不想提供有效的替代方法,将参数error设置为指示失败原因的NSError对象,并返回NO。

      IMPORTANT

      在设置error之前需要测试error参数不为NULL

    • value对象是无效的,但是你知道一个有效的替代方法,创建一个有效的对象,将value的引用指定到新对象,并返回YES(不修改error引用)。如果你提供了其他的value,则始终返回一个新的对象而不是修改正在验证的对象,即使原始对象是可变的。

    下面的代码演示了name属性的验证方法,该方法确保value不是nil,并且名称有一个最小长度。 如果验证失败,此方法不会用另一个值替代。

    - (BOOL)validateName:(id *)ioValue error:(NSError * __autoreleasing *)outError{
        if ((*ioValue == nil) || ([(NSString *)*ioValue length] < 2)) {
            if (outError != NULL) {
                *outError = [NSError errorWithDomain:PersonErrorDomain
                                                code:PersonInvalidNameCode
                                            userInfo:@{ NSLocalizedDescriptionKey
                                                        : @"Name too short" }];
            }
            return NO;
        }
        return YES;
    }
    

    上面我们说了,在设置error之前必须检测error是否为NULL,如果我们没有检测error,而是直接设置error,如下所示:

    - (BOOL)validateName:(id *)ioValue error:(NSError * __autoreleasing *)outError{
        if ((*ioValue == nil) || ([(NSString *)*ioValue length] < 5)) {
            NSErrorDomain PersonErrorDomain = NSCocoaErrorDomain;
            NSInteger PersonInvalidNameCode = 10086;
          // 不检测error是否为`NULL`
            *outError = [NSError errorWithDomain:PersonErrorDomain
                                            code:PersonInvalidNameCode
                                        userInfo:@{ NSLocalizedDescriptionKey
                                                    : @"Name too short" }];
            return NO;
        }
        return YES;
    }
    

    调用检测方法

        Person* person = [[Person alloc] init];
        NSString* name = @"A";
        
        BOOL validation = [person validateValue:&name forKey:@"name" error: nil];
        if (validation) {
            [person setValue:name forKey:@"name"];
        }
    

    这时就会抛出野指针:

    Thread 1: EXC_BAD_ACCESS (code=1, address=0x0)

    基本数据变量的验证

    验证方法期望value参数是一个对象,因此,非对象属性的值将包含在NSValue或NSNumber对象中,如这篇文章所述。 表11-2中的例子演示了基本数据变量age的验证方法。 在这种情况下,通过设置一个有效的@0值来处理一个valuenil的情况,并返回YES。 我们也可以在setNilValueForKey:方法中来处理这种情况,毕竟有时候我们不会调用验证方法。

    示例:

    - (BOOL)validateAge:(id *)ioValue error:(NSError * __autoreleasing *)outError {
        if (*ioValue == nil) {
            // Value is nil: Might also handle in setNilValueForKey
            *ioValue = @(0);
        } else if ([*ioValue floatValue] < 0.0) {
            if (outError != NULL) {
                *outError = [NSError errorWithDomain:PersonErrorDomain
                                                code:PersonInvalidAgeCode
                                            userInfo:@{ NSLocalizedDescriptionKey
                                                        : @"Age cannot be negative" }];
            }
            return NO;
        }
        return YES;
    }
    

    相关文章

      网友评论

          本文标题:KVC之添加验证方法

          本文链接:https://www.haomeiwen.com/subject/lnjorftx.html