10

Can someone walk me through an example of how to use key value validation in IOS? I am confused.

I am writing a Payments SDK, where people pass in credit card number, security code, etc to a Card class, and I need to validate these values. For example, make sure the credit card number is valid.

Is it possible to do automatic validation?

Also, can we call all of the validators at once?

Like if I have a Card class, can I call if([card isValid]) to call all of the validate functions at once without doing so myself? like:

Card * card = [[Card alloc] init];
card.number = @"424242...";
card.securityCode = @"455";
card.expirationMonth = @"";
card.expirationYear = @"";
if([card isValid]) {

Thanks for your help!

Kermit the Frog
  • 3,949
  • 7
  • 31
  • 39
  • What do you mean by "key value validation"? The implementation of your `isValid` method needs to do whatever validation you need. – rmaddy Oct 16 '13 at 21:34
  • 3
    https://developer.apple.com/library/mac/documentation/cocoa/conceptual/KeyValueCoding/Articles/Validation.html#//apple_ref/doc/uid/20002173-CJBDBHCB – Kermit the Frog Oct 16 '13 at 21:44
  • You should know that there are many security implications in storing credit card numbers. – Pier-Luc Gendreau Oct 16 '13 at 22:47
  • @Daij-Djan I did a mobile payment system earlier this year (certified by the banks). I don't recall the name of the international regulation we complied with, but AFAIK you *can* store credit card details in random access memory. – Jasper Blues Oct 20 '13 at 13:22
  • @JasperBlues ah cool, didn't know. Thanks for letting me know – Daij-Djan Oct 20 '13 at 13:23
  • 1
    @Daij-Djan You're right it was. Earlier the comment looked harsh because the question had -1 score and 3 close votes. . Now it seems helpful. Its funny how that colors things. – Jasper Blues Oct 20 '13 at 13:29
  • Hey Jasper, It seems you are a pro at mobile security. Can you also please answer my other question :)? : http://stackoverflow.com/questions/19483309/handling-credit-cards-and-ios – Kermit the Frog Oct 21 '13 at 00:39
  • @SusanJackie This is not really my specialty (I'm a generalist) however I have some experience, which I've shared in an answer. Please vote if it was helpful. – Jasper Blues Oct 21 '13 at 03:56

3 Answers3

6

The link provided by Susan has all the detail you should need. An example implementation would be like this:

- (BOOL)validateSecurityCode:(id *)ioValue 
                       error:(NSError * __autoreleasing *)outError 
{
    // The securityCode must be a numeric value exactly 3 digits long
    NSString *testValue = (NSString *)*ioValue;
    if (([testValue length]!=3) || ![testValue isInteger])) {
        if (outError != NULL) {
            NSString *errorString = NSLocalizedString(
                    @"A Security Code must be exactly 3 characters long.",
                    @"validation: Security Code, invalid value");
            NSDictionary *userInfoDict = @{ NSLocalizedDescriptionKey : errorString };
            *outError = [[NSError alloc] initWithDomain:SECURITYCODE_ERROR_DOMAIN
                                                   code:SECURITYCODE_INVALID_NAME_CODE
                                               userInfo:userInfoDict];
        }
        return NO;
    }
    return YES;
}

Note: I used NSString -isInteger from this post.

The manual says

You can call validation methods directly, or by invoking validateValue:forKey:error: and specifying the key.

The advantage of this is that your - (BOOL)isValid method can be very simply.

- (BOOL)isValid
{
    static NSArray *keys = nil;
    static dispatch_once_t once;
    dispatch_once(&once, ^{
        keys = @[@"securityCode", @"number", @"expirationMonth", @"expirationYear"];
    });

    NSError *error = nil;
    for (NSString *aProperty in keys) {
        BOOL valid = [self validateValue:[self valueForKey:aProperty]
                                  forKey:aProperty
                                   error:&error];
        if (!valid) {
            NSLog("Validation Error: %@", error);
            return NO;
        }
    }
    return YES;
}
Community
  • 1
  • 1
Holly
  • 5,270
  • 1
  • 24
  • 27
2

Here's an example of key-value validation.

According to Apple:

Key-value coding provides a consistent API for validating a property value. The validation infrastructure provides a class the opportunity to accept a value, provide an alternate value, or deny the new value for a property and give a reason for the error.

https://developer.apple.com/library/mac/documentation/cocoa/conceptual/KeyValueCoding/Articles/Validation.html

Method Signature

-(BOOL)validateName:(id *)ioValue error:(NSError * __autoreleasing *)outError {
    // Implementation specific code.
    return ...;
}

Properly calling the method

Apple: You can call validation methods directly, or by invoking validateValue:forKey:error: and specifying the key.

Ours:

//Shows random use of this
    -(void)myRandomMethod{

        NSError *error;

        BOOL validCreditCard = [self validateCreditCard:myCreditCard error:error];
    }

Our test implementation of your request

    //Validate credit card
    -(BOOL)validateCreditCard:(id *)ioValue error:(NSError * )outError{

        Card *card = (Card*)ioValue;

        //Validate different parts
        BOOL validNumber = [self validateCardNumber:card.number error:outError];
        BOOL validExpiration = [self validateExpiration:card.expiration error:outError];
        BOOL validSecurityCode = [self validateSecurityCode:card.securityCode error:outError];

        //If all are valid, success
        if (validNumber && validExpiration && validSecurityCode) {
            return YES;

            //No success
        }else{
            return NO;
        }
    }

    -(BOOL)validateExpiration:(id *)ioValue error:(NSError * )outError{

        BOOL isExpired = false;

        //Implement expiration

        return isExpired;
    }

    -(BOOL)validateSecurityCode:(id *)ioValue error:(NSError * )outError{

    //card security code should not be nil and more than 3 characters long
    if ((*ioValue == nil) || ([(NSString *)*ioValue length] < 3)) {

        //Make sure error us not null
        if (outError != NULL) {

            //Localized string
            NSString *errorString = NSLocalizedString(
                                                      @"A card's security code must be at least three digits long",
                                                      @"validation: Card, too short expiration error");

            //Place into dict so we can add it to the error
            NSDictionary *userInfoDict = @{ NSLocalizedDescriptionKey : errorString };

            //Error
            *outError = [[NSError alloc] initWithDomain:CARD_ERROR_DOMAIN
                                                   code:CARD_INVALID_SECURITY_CODE
                                               userInfo:userInfoDict];
        }
        return NO;
    }
    return YES;
}

    -(BOOL)validateCardNumber:(id *)ioValue error:(NSError * )outError{

        BOOL isValid = false;

        //Implement card number verification

        return isValid;
    }
William Falcon
  • 9,813
  • 14
  • 67
  • 110
0

Key Value Coding (KVC) Validation is for validating a single value that you want to put in a specific property. It is not automatic and you should never invoke a validation method within the -set accessor for a property. The intended use (at least the way I've seen it used in Apple samples or used it myself) is to validate input from the user before mutating your object. On Mac OSX applications with Cocoa Bindings this is very useful, but on iOS not so much.

I don't believe KVC Validation is what you are looking for since you want to check that all of an objects property values are valid. As others have posted you could make it work, but it would add complexity without any significant benefit.

RyanR
  • 7,728
  • 1
  • 25
  • 39
  • OP is asking specifically about KVV, as documented here: https://developer.apple.com/library/mac/documentation/cocoa/conceptual/KeyValueCoding/Articles/Validation.html#//apple_ref/doc/uid/20002173-CJBDBHCB – Jasper Blues Oct 20 '13 at 15:44
  • Yep, that's the same article I linked to, except I used the iOS version since the question is tagged iOS. – RyanR Oct 20 '13 at 16:03