Binding JSON to Data Objects using KVC

DZone 's Guide to

Binding JSON to Data Objects using KVC

Working with JSON data in iOS is pretty straightforward. However, there is an even simpler solution: key-value coding (KVC).

· Mobile Zone ·
Free Resource

Working with JSON data in iOS is pretty straightforward. For example, suppose you're writing an application that retrieves some simple statistical information from a web service:

{"count": 3, "sum": 9.0, "average": 3.0}

You might load the data from the server, call the JSONObjectWithData method of NSJSONSerialization, and retrieve the values from the deserialized dictionary:

NSDictionary *dictionary = [NSJSONSerialization JSONObjectWithData:data options:0 error:&error];

NSLog(@"%d", [[dictionary objectForKey:@"count"] intValue]); // prints 3
NSLog(@"%.1f", [[dictionary objectForKey:@"sum"] doubleValue]); // prints 9.0
NSLog(@"%.1f", [[dictionary objectForKey:@"average"] doubleValue]); // prints 3.0

However, sometimes it is preferable to work with more strongly typed data objects in an application. For example, you might create a Statistics class to represent the data returned by the web service:

@interface Statistics : NSObject

@property (nonatomic) int count;
@property (nonatomic) double sum;
@property (nonatomic) double average;


You could then populate your object by extracting the values from the dictionary as follows:

Statistics *statistics = [[Statistics alloc] init];

statistics.count = [[dictionary objectForKey:@"count"] intValue];
statistics.sum = [[dictionary objectForKey:@"sum"] doubleValue];
statistics.average = [[dictionary objectForKey:@"average"] doubleValue];

To make things easier and avoid code duplication, you might put this code in an initializer for the Statistics class:

- (instancetype)initWithDictionary:(NSDictionary *)dictionary {
    self = [super init];

    if (self) {
        self.count = [[dictionary objectForKey:@"count"] intValue];
        self.sum = [[dictionary objectForKey:@"sum"] doubleValue];
        self.average = [[dictionary objectForKey:@"average"] doubleValue];

    return self;

Your code for binding the JSON response to the Statistics instance would then be reduced to this:

Statistics *statistics = [[Statistics alloc] initWithDictionary:dictionary];

In either case, you could then access the data returned from the server using the strongly-typed properties of your data object:

NSLog(@"%d", statistics.count); // prints 3
NSLog(@"%.1f", statistics.sum); // prints 9.0
NSLog(@"%.1f", statistics.average); // prints 3.0

This works reasonably well, and it is undoubtedly a common approach to mapping JSON content to strongly typed data objects.

However, there is an even simpler solution: key-value coding (KVC). The setValuesForKeysWithDictionary: method of NSObject can be used to automatically apply all values in a given dictionary to an object's properties. Using this approach, the initWithDictionary: method can be reduced to the following:

- (instancetype)initWithDictionary:(NSDictionary *)dictionary {
    self = [super init];

    if (self) {
        [self setValuesForKeysWithDictionary:dictionary];

    return self;

No manual mapping of dictionary entries to property values is required. Simply declaring the properties using the appropriate name and type is sufficent.

It also works in Swift:

class Statistics: NSObject {
    var count: Int = 0
    var sum: Double = 0
    var average: Double = 0

    init(dictionary: [String: AnyObject]) {


Further, if you need to customize the assignment of any property names or values, you can do so easily by overriding setValue:forKey:. For example, suppose the server refers to the average property by a different name (e.g. "mean"):

{"count": 3, "sum": 9.0, "mean": 3.0}

You could override setValue:forKey: to ensure that this value is mapped to the correct property:

- (void)setValue:(id)value forKey:(NSString *)key {
    if ([key isEqual:@"mean"]) {
        key = @"average";

    [super setValue:value forKey:key];

Finally, you can use KVC to easily ignore values. For example, suppose the server response additionally contains a "median" property:

{"count": 3, "sum": 9.0, "average": 3.0, "median": 3.0}

Since the Statistics class does not define a median property, setValuesForKeysWithDictionary: will throw an NSUnknownKeyException. You can avoid this exception by simply overriding the setValue:forUndefinedKey: method:

- (void)setValue:(id)value forUndefinedKey:(NSString *)key {
    // No-op

Published at DZone with permission of Greg Brown , DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}