Reputation: 3969
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!
Upvotes: 10
Views: 2540
Reputation: 5300
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;
}
Upvotes: 6
Reputation: 9813
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.
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;
}
Upvotes: 2
Reputation: 7758
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.
Upvotes: 0