iOS Property Validation Built on KVC

March 5, 2013 — Written with Nick Cipollina

Validation is always necessary when accepting input directly from users or remote servers, however it can quickly consume valuable development time to get it right. This post describes a pattern that builds on the foundations of Key-Value Coding (KVC) to automatically perform standard validation and also provides a framework for more complex processing. We will begin with a high-level overview of standard KVC and some common pitfalls, then describe our validation pattern and walk you through an example app demonstrating its benefits. If you'd like to skip right to the sample code, click here to jump to the Sample App section or click here for the source on GitHub.

The Basics of Key-Value Coding

KVC is a system of accessing and setting properties on an Objective-C object using the string name of the property instead of calling the getter or setter method directly. If you are new to KVC, the Key-Value Coding Programming Guide is an excellent overview of the concepts involved. The pattern is codified in the NSKeyValueCoding informal protocol, which includes methods like valueForKey: (a generic getter) and setValue:forKey (a generic setter). The two lines of code below that set the name property have the exact same effect:

	Employee *somebody = [[Employee alloc] init];
	// without KVC = @"Bill";
	// with KVC
	[somebody setValue:@"Bill" forKey:@"name"];
Other methods accept a key path argument, which is a list of keys to traverse separated by a period. Key paths are a great way to save boilerplate code, for example to get the phone extension of Bill's manager:
	// without KVC
	Employee *manager = bill.manager;
	PhoneNumber *phone = manager.phoneNumber;
	Extension *ext = phone.extension;
	// with KVC
	Extension *ext = [bill valueForKeyPath:@"manager.phoneNumber.extension"];
The most important detail to note is that the key path is case-sensitive. Using @"manager.phonenumber.extension" would not work unless Employee had both "phoneNumber" and "phonenumber" properties. Case sensitivity becomes important when you encounter data that comes from an external source and could potentially change case at any time (Pitfall #1).

One non-obvious KVC behavior is that calling setValue:forKey: on an NSArray will not fail because arrays don't have keys, but instead will call setValue:forKey: on each object it contains.

KVC's most common use is when serializing or deserializing objects, a process that happens more often than you might think. If your app stores object data on disk or transmits it across a network, then you are most likely already using KVC under the hood. For example, Core Data uses it to translate between its object representation and the underlying persistent store. Other common uses are when parsing JSON web service results into an existing object or using an NSKeyedArchiver to serialize an object for storage or transmission. Typically you create an initWithDictionary: initializer to ingest dictionaries created by NSJSONSerialization or implement NSCoding for more explicit serialization support. The initWithDictionary: method used in the sample app simply turns around and uses KVC:

	- (id)initWithDictionary:(NSDictionary *)dictionary {
		self = [self init];
		if (self){
			[self setValuesForKeysWithDictionary:dictionary];
		return self;
The one caveat to this is that you should implement setValue:forUndefinedKey: to cover the case where the given dictionary has keys for properties that don't exist. The default implementation by NSObject simply throws an NSUndefinedKeyException, which is almost certainly not what you want (Pitfall #2).

Another pitfall with KVC is a lack of type checking (Pitfall #3). This behavior follows naturally from Objective-C's dynamic nature, however it will definitely lead to very bizarre bugs further in the development process. KVC will happily let you assign an NSNumber to an NSString property at runtime, and you will be scratching your head when you later try to determine the length of that string and the app immediately crashes. For example, an NSString property name on an Employee bill:

	[bill setValue:[NSNumber numberWithInteger:1] forKey:@"name"]; // compiles and runs = [NSNumber numberWithInteger:1]; // won't compile: Incompatible pointer types assigning to 'NSString *' from 'NSNumber *'
Because the value parameter in setValue:forKey: is id, it will accept any pointer you send it, and the discrepancy will only come to light when you use the value. Inadvertent type changes can commonly happen when an API switches JSON parsers or changes something internally and different values are generated for the same keys.

KVC includes support for validation that could catch these type mismatches, but it requires explicit coding on your part (Pitfall #4). NSKeyValueCoding includes validateValue:forKey:error: and validateValue:forKeyPath:error: to help you with any custom validation logic you want to implement. The default implementations will search for a method that has the pattern validate{key name}:error: and call it if it exists. While this behavior is handy, it can be very tedious to add validation to a class with a dozen or more properties.

The other drawback with the built-in validation is that the validation logic is not automatically run (Pitfall #5). The expectation is that as the developer, you will call either validateValue:forKey: before setting a key's value or validate{key name}:error: yourself. While there may be some specific cases that you would want this flexibility, in general the whole process can be easily overlooked, yielding invalid data.

	@property (nonatomic, strong) NSString firstName;

	- (BOOL)validateFirstName:(id*)ioValue error:(NSError**)error {
		// Validation logic goes here

	Person *p = [Person new];
	NSString *firstName = @"Bill";
	NSError *error = nil;

	// This call below actually calls our validateFirstName: error: method
	if ([p validateValue:&firstName forKey:@"firstName" error:&error]) {
		[p setValue:firstName forKey:@"firstName"];
As you can see, that is a lot of code to validate just a single property before setting it. If Person had twenty properties, imagine the amount of code you would have to add to this class to validate all of them. Now consider writing that code for every class in the project, and you can see how quickly you would get bogged down just writing validation logic.

Building on KVC Validation

Now that you have an understanding of KVC's built-in validation, we can expand on it and improve the five pitfalls we identified. Our pattern's goals:

  1. Supporting case-insensitivity for key names
  2. Automatically checking property types
  3. Automatically creating and using validate{key name}: methods
  4. Mapping keys to properties with different names
Goals 1 and 3 will require some dynamic runtime logic, and goal 2 will use the type validators we have packaged with this post's example app. The type validators will do more than just a class check; they are flexible enough to attempt to convert some invalid types or values into valid ones whenever possible. Goal 4 requires a mapping dictionary to be created by the programmer, but all other logic happens automatically.

Case Insensitivity

To tackle case insensitivity, any class inheriting from the base model object will determine its own properties and their types, and repeat the process for its superclass(es). For each property, it will build a mapping dictionary that maps the lowercase version of the property name to the actual property name. Whenever we need to operate on an ambiguously-cased key, we can simply lowercase it and look up the real name in this mapping dictionary. The base model class has a static NSDictionary that stores this property information for each distinct subclass. The population of these class-specific details happens in initialize because of it will always be called before the class is used:

Initializes the receiver before it’s used (before it receives its first message).

+ (void)initialize

The runtime sends initialize to each class in a program exactly one time just before the class, or any class that inherits from it, is sent its first message from within the program. (Thus the method may never be invoked if the class is not used.) The runtime sends the initialize message to classes in a thread-safe manner. Superclasses receive this message before their subclasses.

	+ (void)initialize {
		[super initialize];
		dispatch_once(&onceToken, ^{
			modelProperties = [NSMutableDictionary dictionary];
			propertyTypesArray = @[/* removed for brevity */];
		NSMutableDictionary *translateNameDict = [NSMutableDictionary dictionary];
		[self hydrateModelProperties:[self class] translateDictionary:translateNameDict];
		[modelProperties setObject:translateNameDict forKey:[self calculateClassName]];
	+ (void)hydrateModelProperties:(Class)class translateDictionary:(NSMutableDictionary *)translateDictionary {
		if (!class || class == [NSObject class]){
		unsigned int outCount, i;
		objc_property_t *properties = class_copyPropertyList(class, &outCount);
		for (i = 0; i < outCount; i++){
			objc_property_t p = properties[i];
			const char *name = property_getName(p);
			NSString *nsName = [[NSString alloc] initWithCString:name encoding:NSUTF8StringEncoding];
			NSString *lowerCaseName = [nsName lowercaseString];
			[translateDictionary setObject:nsName forKey:lowerCaseName];
			NSString *propertyType = [self getPropertyType:p];
			[self addValidatorForProperty:nsName type:propertyType];
		[self hydrateModelProperties:class_getSuperclass(class) translateDictionary:translateDictionary];
Note that hydrateModelProperties:translateDictionary: is called recursively until it hits the base class (where class is nil) or NSObject. Now if a class needs to set keys like "firstName" or "firstname" or "FIRSTNAME", each will get lowercased and matched to the real property. The ambiguously-cased value can be sent into setValue:forKey:, which will determine the proper case automatically:
	- (void)setValue:(id)value forKey:(NSString *)key {
		[self setValue:value forKey:key properCase:NO];
	- (void)setValue:(id)value forKey:(NSString *)key properCase:(BOOL)properCase {
		if (!properCase) {
			NSString *lowerCaseKey = [key lowercaseString];
			NSString *properKey = modelProperties[self.dictionaryKey][lowerCaseKey];
			if (properKey){
				key = properKey;
		[super setValue:value forKey:key];

Type Checking & Validation Methods

Checking each value before setting it was goal #2, and it also uses some runtime logic to determine the type of each property and hooks up the appropriate validator for that type. The type determination is done in initialize at the same time as the property names are queried. The Objective-C runtime returns property types from property_getName(objc_property_t property), and the values differ between primitive types and objects. Objects return a C-string of the class name, while primitive types return the value given by the @encode() function. Our pattern uses the propertyTypesArray to convert between the return values and an enum CTCPropertyType. The array is declared such that the value of the enum matches the index of the equivalent C-string:

	typedef NS_ENUM(NSUInteger, CTCPropertyType){
		CTCPropertyUnknown = 0,				// Property type is unknown
		CTCPropertyTypeString,				// Property is an NSString
		CTCPropertyTypeBool,				// Property is a BOOL
		CTCPropertyTypeNumber,				// Property is an NSNumber
		CTCPropertyTypeInteger,				// Property is an NSInteger
		CTCPropertyTypeFloat,				// Property is a float
		CTCPropertyTypeArray,				// Property is an NSArray
		CTCPropertyTypeMutableArray,		// Property is an NSMutableArray
		CTCPropertyTypeDictionary,			// Property is an NSDictionary
		CTCPropertyTypeMutableDictionary,	// Property is an NSMutableDictionary
		CTCPropertyTypeUnsignedInteger,		// Property is an NSUInteger
		CTCPropertyTypeDate,				// Property is an NSDate
		CTCPropertyTypeDouble				// Property is a double
	// note this array's indexes MUST match the CTCPropertyType enum values for lookups to work properly
	propertyTypesArray = @[@"Unknown",
						   [NSString stringWithFormat:@"%s",@encode(BOOL)],	
						   [NSString stringWithFormat:@"%s",@encode(int)],
						   [NSString stringWithFormat:@"%s",@encode(float)],
						   [NSString stringWithFormat:@"%s",@encode(unsigned int)],
						   [NSString stringWithFormat:@"%s",@encode(double)]];
Once we have identified the matching enum value for each property, we hook up the appropriate validate{key name}:error: method by dynamically creating it on the spot. This way we get the same behavior as the normal KVC validation without having to explicitly code dozens of validate methods. It will also play nicely with any validate{key name}:error: methods that happen to already exist. For example, the sample app's CTCStation has some validate{key name}:error: methods defined at compile time and some added at run time. The dynamic implementations have been defined in ValidationFunctions.h and follow the form:
	BOOL validateStringProperty(id self, SEL _cmd, id *ioValue, NSError *__autoreleasing* outError){
		CTCStringTypeValidator *validator = [CTCStringTypeValidator new];
		return [validator validateValue:ioValue error:outError];
The validators inherit from a base validator that has two actions: a validation action and a post validation action. Each is represented by a block, which allows you to tweak how it works without making a new subclass. The validation action returns the validated/scrubbed value or a default one and updates the isValid flag as appropriate:
	self.defaultValidation = ^NSString *(id value, BOOL *isValid, NSError **error){
		if ([value respondsToSelector:@selector(stringValue)]){
			*isValid = YES;
			return [value stringValue];
		} else {
			*isValid = NO;
			return nil;
The isValid flag is important because it allows you to attempt to massage an invalid value into a valid one. The example above shows turning any non-NSString class that implements stringValue (say NSNumber) into the equivalent string. Because we were able to do this manipulation, the app is able to receive invalid data but still perform as if we had received what we expected. If we aren't able to fix the invalid data, we don't have any choice but to set isValid to NO and give up. Note that the defaultValidation block does not need to do a type check because the super implementation does one before calling the defaultValidation block:
	- (BOOL)validateValue:(id *)value error:(NSError **)error {
		_isValid = [*value isKindOfClass:[NSString class]];
		return [super validateValue:value error:error];
A good example of the post-validation action is in this zip code validator that ensures any zip code less than 5 digits is padded with zeroes:
	_zipValidator = [CTCStringTypeValidator new];
	_zipValidator.postValidation = ^NSString *(id value){
		value = [NSString leftPadString:value length:5 padCharacter:@"0"];
		return value;
Notice that it is actually a string validator and didn't require a special subclass because we simply changed the block's logic. Also notice that there is no type checking or validation of any kind in the postValidation block. This is because the post-validation logic is only run if the value is valid. The block is not intended to make any changes to the value itself, but perhaps to format it for display to the user. Other examples might be formatting a price string with an NSNumberFormatter or ensuring that a state abbreviation is always shown in uppercase.

Once the validator steps have been performed, the process ends in the base model's setValue:forKey:properCase:, which finally sets the scrubbed and validated value using the super class's (which is NSObject) setValue:forKey: if the value has been deemed valid. If the validator was unable to validate the value, the value is not set at all.

We know it can be confusing to follow the line of execution between the model object, validators, and KVC itself, so we put together an example app that uses the entire pattern. If you understand the individual pieces but aren't clear how they fit together, the "Sample Validation App" section is just for you.

Mapping Keys to Properties with Different Names

In certain scenarios an object might logically have a data element with the same name as a reserved Objective-C keyword (commonly "id" or "description") or a name that doesn't fit with how you have your object structured. KVC provides setValue:forUndefinedKey: for those scenarios, but the mapping process has to be done manually in each subclass. In our pattern, the base model object has an undefinedKeys dictionary that maps from the received key name to the actual property name. Some of these mappings can be done globally and others can be set by specific subclasses. A good candidate for a global mapping would be changing "id" to "identifier" and a specific case might be to map "description" to "name":

	- (NSDictionary *)undefinedKeys {
		static NSDictionary *undefinedKeys;
		static dispatch_once_t onceToken;
		dispatch_once(&onceToken, ^{
			undefinedKeys = @{@"description": @"stationName"};
		return undefinedKeys;
It's important to note that the key should always be lowercase and the mapped property name should be cased the same way as the actual property definition. The implementation for setValue:forUndefinedKey: simply looks up the given key in the undefinedKeys dictionary and ignores any it does not find.
	- (void)setValue:(id)value forUndefinedKey:(NSString *)key {
		NSString *newKey = self.undefinedKeys[[key lowercaseString]];
		if (newKey){
			[self setValue:value forKey:newKey properCase:YES];

Sample Validation App

The sample app "KVC Validation Pattern" implements a gas price comparison app that relies on crowd-sourced data in the same vein as GasBuddy or other similar services. We chose this scenario because of the inherent unpredictability of user-generated data that makes validation an essential piece of the app. The app includes five stubbed out JSON responses that have various changes in the data that should be handled by the app. The code can be found on GitHub at

In cases where the data can be manipulated into the expected format, we do that conversion, but in the worst case we assign a default value that won't crash the app or leave holes in the user interface. When running the app you should see identical UI between Response A, B, and D; Response C should be the same but have a price of $4.00; and Response E should have only default/blank data. These represent scenarios of increasing divergence between the data structure the app expects versus what is present in the JSON itself.

The next sections will walk through the execution path for validation of certain properties in the stubbed JSON responses. Calls in blue are ones that would be made using standard KVC and all others are specific to this pattern.

Response A: The Happy Path

The following JSON is the happy path description of a gas station. Each property is the proper type and value the app expects, and this response will be the baseline against which to compare responses B through E.

Screenshot of Response A

		"description":"7/11 Fake St.",
		"sellsDiesel": true,
		"address": {
			"street":"123 Fake Street",
We are going to trace the execution path of the "price" element and then compare that to extra mapping that is required for "description". This pseudo stack trace is most helpful if you have the code open as well and can jump through the source files as you go through each step. Remember that calls in blue are ones that would be made using standard KVC and all others are specific to this pattern.
  1. CTCStationinitWithDictionary:<NSDictionary including "price"=3.5>
  2. NSObject<NSKeyValueCoding>setValuesForKeysWithDictionary:<NSDictionary including "price"=3.5>
  3. CTCBaseModelsetValue:<NSNumber: 3.5> forKey:@"price"
  4. CTCBaseModelsetValue:<NSNumber: 3.5> forKey:@"price" properCase:NO
    Performs the lookup to get the properly-cased property name
  5. CTCBaseModelvalidateValue:<NSNumber: 3.5> forKey:@"price" error:<NSError>
  6. CTCStationvalidatePrice:<NSNumber: 3.5> error:<NSError>
    This is the method we added dynamically
  7. CTCNumberTypeValidatorvalidateValue:<NSNumber: 3.5> error:<NSError>
    isValid was set to YES here because the types match
  8. CTCBaseValidatorvalidateValue:<NSNumber: 3.5> error:<NSError>
    This method sees that isValid is YES and calls the postValidation block if necessary
  9. NSObject<NSKeyValueCoding>setValue:<NSNumber: 3.5> forKey:@"price"
  10. CTCStationsetPrice:3.5f
  11. the price property becomes 3.5f
The validation logic for "description" follows a similar path but replaces step #2 with two different steps because "description" is a reserved method name in Objective-C. CTCStation initializes the undefinedKeys to map it to the stationName property:

	undefinedKeys = @{@"description": @"stationName"};

  1. CTCStationinitWithDictionary:<NSDictionary including "description"="7/11 Fake St.">
  2. NSObject<NSKeyValueCoding>setValuesForKeysWithDictionary:<NSDictionary including "description"="7/11 Fake St.">
  3. CTCBaseModelsetValue:@"7/11 Fake St." forUndefinedKey:@"description"
    The undefinedKeys dictionary is used here to find the new key name "stationName". Because the programmer intentionally set up this mapping, we assume it is already properly-cased.
  4. CTCBaseModelsetValue:@"7/11 Fake St." forKey:@"stationName" properCase:YES
  5. CTCBaseModelvalidateValue:@"7/11 Fake St." forKey:@"stationName" error:<NSError>
  6. CTCStationvalidateStationName:@"7/11 Fake St." error:<NSError>
  7. CTCStringTypeValidatorvalidateValue:@"7/11 Fake St." error:<NSError>
    isValid was set to YES here because the types match
  8. CTCBaseValidatorvalidateValue:@"7/11 Fake St." error:<NSError>
    This method sees that isValid is YES and calls the postValidation block if necessary
  9. NSObject<NSKeyValueCoding>setValue:@"7/11 Fake St." forKey:@"stationName"
  10. CTCStationsetStationName:@"7/11 Fake St."
  11. the stationName property becomes @"7/11 Fake St."

Response B: Type Changes

Response B is logically equivalent to Response A, however four elements have changed their types.

Screenshot of Response B

		"description":"7/11 Fake St.",
		"sellsDiesel": "yes",
		"address": {
			"street":"123 Fake Street",
Notable changes:
  • both "price" elements change from a numeric type (3.5) to a string ("$3.50")
  • "sellsDiesel" changes from a boolean (true) to a string ("yes")
  • "zip" changes from a string ("07105") to a numeric type (7105)
This JSON demonstrates how the validation logic can transform unexpected but logically similar data in into the proper format. This execution trace follows the processing for the first "price" element for easy comparison to the one from Response A:
  1. CTCStationinitWithDictionary:<NSDictionary including "price"="$3.50">
  2. NSObject<NSKeyValueCoding>setValuesForKeysWithDictionary:<NSDictionary including "price"="$3.50">
  3. CTCBaseModel - setValue:@"$3.50" forKey:@"price"
  4. CTCBaseModelsetValue:@"$3.50" forKey:@"price" properCase:NO
  5. CTCBaseModelvalidateValue:@"$3.50" forKey:@"price" error:<NSError>
  6. CTCStationvalidatePrice:@"$3.50" error:<NSError>
  7. CTCNumberTypeValidatorvalidateValue:@"$3.50" error:<NSError>
    isValid was set to NO here because the types (NSNumber vs. NSString) did not match
  8. CTCBaseModelValidatorvalidateValue:@"$3.50" error:<NSError>
  9. CTCFloatTypeValidatordefaultValidation(@"$3.50", NO, <NSError>) block
    Determines that value is a string and strips non-numeric characters, then checks for floatValue, calls it, and wraps the result in an NSNumber.
  10. NSObjectsetValue:<NSNumber: 3.5> forKey:@"price"
  11. CTCStationsetPrice:3.5f
  12. the price property becomes 3.5f
The logic diverges at step 7 when isValid is NO in this case, and value is sent to the validator to be manipulated (via the floatValue call) into the type we expect. The execution logic for "sellsDiesel" is also interesting because it demonstrates how the boolean validator is able to transform certain strings into valid YES or NO values:
  1. CTCStationinitWithDictionary:<NSDictionary including "sellsDiesel"="yes">
  2. NSObject<NSKeyValueCoding>setValuesForKeysWithDictionary:<NSDictionary including "sellsDiesel"="yes">
  3. CTCBaseModelsetValue:@"yes" forKey:@"sellsDiesel"
  4. CTCBaseModelsetValue:@"yes" forKey:@"sellsDiesel" properCase:NO
  5. CTCBaseModelvalidateValue:@"yes" forKey:@"sellsDiesel" error:<<NSError>
  6. CTCStationvalidateSellsDiesel:@"yes" error:<NSError>
  7. CTCNumberTypeValidatorvalidateValue:@"yes" error:<NSError>
    isValid was set to NO here because the types (NSNumber vs. NSString) did not match
  8. CTCBaseModelValidatorvalidateValue:@"yes" error:<NSError>
  9. CTCBooleanTypeValidatordefaultValidation(@"yes", NO, <NSError>) block
    Determines that the NSString matches one of our predefined YES equivalent strings, then wraps the YES in an NSNumber.
  10. NSObjectsetValue:<NSNumber: YES> forKey:@"sellsDiesel"
  11. CTCStationsetSellsDiesel:YES
  12. the sellsDiesel property becomes YES

Response C: Further Type Changes

Response C takes type changes even further to demonstrate additional flexibility in the various validator classes.

Screenshot of Response C

		"description":"7/11 Fake St.",
		"sellsDiesel": 1,
		"address": {
			"street":"123 Fake Street",
Notable changes:
  • "price" elements changes from a decimal type (3.5) to an integer (4)
  • "sellsDiesel" changes from a boolean (yes) to an integer (1)
  • "date" changes from an ISO date (2013-02-18T15:43:24-05:00) to a UNIX timestamp (1361202204)
The execution traces don't differ meaningfully from Response B but do demonstrate the wide range of values the validation pattern can accommodate.

Response D: Unexpected Structure

Response D shows how a validator responds to input with unexpected structure.

Screenshot of Response D

The "historicalPrice" element changes from an array of objects into just an object (note the lack of square brackets):
		"description":"7/11 Fake St.",
		"sellsDiesel": true,
		"address": {
			"street":"123 Fake Street",
This scenario happens more than you might expect with some JSON generators. Some systems (e.g. Jettison) that convert from other formats will see a single element in a collection and output that as a solitary element instead of an array that contains one element. CTCStation uses a normal KVC validation method, validateHistoricalPrices:error:, to handle this case, but does the validation logic using an array validator with custom logic. It assumes that if the type is not an array, then it should be parsed as if it was an array containing the solitary element.
	- (BOOL)validateHistoricalPrices:(id *)ioValue error:(NSError *__autoreleasing *)outError{
		dispatch_once(&_historyToken, ^{
			// if this happens to be a single object (i.e. a dictionary) then assume it was supposed to be an array of one element
			_historyValidator = [[CTCArrayTypeValidator alloc] initWithDefaultValidation:^NSArray *(id value, BOOL *isValid, NSError **error){
				if ([value isKindOfClass:[NSDictionary class]]){
					*isValid = YES;
					return @[value];
				return nil;
			// take the array we are given and process its contents as CTCHistoricalPrice objects
			_historyValidator.postValidation = ^NSArray *(id value){
				NSMutableArray *histories = [NSMutableArray array];
				for (NSDictionary *dict in value){
					CTCHistoricalPrice *price = [[CTCHistoricalPrice alloc] initWithDictionary:dict];
					[histories addObject:price];
				return histories;
		return [_historyValidator validateValue:ioValue error:outError];

Response E: Further Unexpected Structure

Response E represents the case where the actual JSON structure has diverged so much from the expected structure that the app can no longer overcome the differences with flexible validation logic.

Screenshot of Response E

A mix of null values and error messages simulate the catastrophic failure of some backend system:
		"sellsDiesel": null,
		"address":"error looking up address",
		"historicalPrices":"error fetching prices"
In this case the app has no chance of giving the user the data he or she requested, but the least it can do is populate default values and ensure it doesn't crash. The various validators each define a default value that is used in place of invalid values that can't be manipulated into a valid value. Typically these values are the logical equivalent of 0 or nil for that property type, however different values can always be substituted if certain situations require them.

In this post, we covered the basics of KVC and KVC validation. We talked about some of the inherent issues with KVC validation and how it works. We identified and implemented four goals for an improved validation pattern: case-insensitivity for key name, type checking, automatic creation of property validation methods, and easy remapping of keys to properties with different names. A sample app demonstrates the improved pattern in the context of crowd-sourced gas price tracking, where flexible validation logic can recover from the unpredictability of the available data.

The sample app can be found on GitHub at


  • Sorry, Twitter is unavailable or some other error occured. #fail