Blog

Using Cocoa’s KVC to Parse JSON

     
By on March 8, 2014 - 7 Minutes

croped_leaf

“Everything has beauty, but not everyone sees it”, Confucius

Introduction

As you might know, JSON is an open standard format that uses human-readable text to transmit data objects consisting of attribute–value pairs. People like this format because it is easy to handle and very straight-forward to understand.

Consequently, it is a very common feature for Mobile Apps to perform connections to servers and fetch remote JSON data. This data must be then parsed and converted into client model objects. This action is something that may happen very often and should be done fast and efficiently. Also, because the server may change the JSON data, adding or removing new fields, our parsing system must be flexible and scalable.

From raw JSON data to data structures

The first step consists in transform JSON data into a usable data structure. This problem is something that has already been solved by Apple using the class NSJSONSerialization. It converts the JSON data into a NSDictionary or NSArray, depending on the JSON.

Perfect, now we have our JSON data inside a usable data structure, but this doesn’t solve our problem. We need to convert JSON data structures to custom model objects and this is a complete different problem.

Model Object Mapping

Here the problem is how to convert (or map) a NSDictionary, representation of JSON data, into a custom object. Multiple approaches can be found in order to solve this problem and we need to find the more simple, scalable and straight-forward one.

1. The Parser Object

We could create a “Parser” object that is responsible of performing the parsing of our objects (probably being a singleton). For example, the class could have methods like -userObjectFromDictionary: that would create a “user object” from the “user JSON data”, and a many other methods, one per each entity to be parsed.

However, this first parsing pattern is non-distributed, meaning all parsing code is located in a single place and model-code-sharing needs to be complimented with external parsing methods.

2. Distributed Parsing

Another approach is to do the parsing in a distributed way, having a superclass for our model objects like:

Both methods “init” and “parse” would map the dictionary keyed-values into their properties and maybe, create other objects and parse them using this recursive pattern.

Issues

However there is a recurrent action that is present in all of them: you must map manually each key-value of the dictionary to your object attribute. Even more, in order to avoid overriding attributes for its key-values that are not in the given dictionary, we must test for each attribute if the key-value is present in the dictionary and if yes, parse that specific key-value for each object attribute.

The above lines will have to be coded per each attribute. This is a lot of code. Can you imagine? I’m sure you do.

Also, if we need to support multiple JSON keys for a single attribute or JSON key versioning for different backend versions, the thing becomes even harder: plenty of if statements, lots of casuistic and a code that is becoming hard to maintain and easy breakable.

Therefore, we would like to find a simple, elegant, scalable and automatised solution.

Simplifying with KVC

If we look more in detail, the only think that we must do for sure is define a mapping between the JSON keys and our object properties. Once this is defined, we can feel that everything else can be automatised, and this is what we are going to accomplish with Cocoa’s KVC pattern.

Understanding what is KeyValueCoding (KVC)

We can check in Apple’s documentation of KeyValueCoding:

Key-value coding is a mechanism for accessing an object’s properties indirectly, using strings to identify properties, rather than through invocation of an accessor method or accessing them directly through instance variables

In other words, KVC is a mechanism that allows you to access object properties using strings. What does that mean? easy, you can get and set the value of an object just using a string with its name.

For example, having the following class:

The following code:

can be written using Key Value Coding as:

KeyValueCoding has more functionalities and usages, but with this we have enough for creating model object mapping from a JSON object or a NSDictionary.

Adapting KVC for Model Object Mapping

The main idea is to create a mapping from JSON keys to object attributes names. Then in the object parsing method we can map the JSON key to the object attribute name and perform via KVC the setting of the attribute. We are going to define this into a custom category on NSObject, so magically, all objects in your project will be “parseable” if they implement the mapping from JSON to attribute names.

The interface would be like:

The first method, -mappingForKVCParsing, should return a dictionary with the mapping from the JSON keys to the object property names. The second method sets a value for a specific key. This key is going to be mapped using the dictionary returned by -mappingForKVCParsing. Finally, the last method will set the key-values contained in the dictionary using the same pattern as described in the second method.

Here we can find the implementation of these methods:

Remark that we are calling the KVC validation method before setting the value via KVC. This will allow the developer to check if the value type is correct or if it should be converted (or parsed) into another type of object before the setting is done.

To understand how this system will work, lets give an example.

Sample parsing via KVC

Let’s reuse our video class listed above, that should be parsed from the following JSON:

In order to use the KVCParsing category we need to override the method -mappingForKVCParsing and validate those fields that doesn’t fit the type of the object:

Therefore, now you can parse your Video objects (and your User objects) by simply doing:

Benefits of using KVCParsing

Distributed parsing pattern
Each object is responsible of its own parsing. Using the KVCParsing category on NSObject this is even more evident, thus now all NSObject may be parseable.

Minimising code
The only code you must implement for parsing an object is the server-object mapping and the specific cases of data value validation. The rest is automatic. We have reduced the amount of code you have to do to the minimum.

Only interacting with the received key-values
Because KVC will only set those key-values you are setting, you won’t be interacting with the others available keys or properties of your objects. No need to test if your dictionary contains or not a key-value in order to avoid overriding it with a nil value.

Non-injective mappings
You can define non-injective mappings to your object properties. This means you can establish multiple JSON names for a single property. This is very useful if your backend service is not consistent with names.

Logging undefined keys
If you try to set a property via KVC with an undefined key, the system by default will throw an exception and stop your application. However, you can override the KVC method -setValue:forUndefinedKey: and you will be able to handle those values for undefined keys. You can log them and know when the server is sending unknown key-values or anything else you want.

Simple, Powerful & Scalable
We have designed a very simple but powerful system. You can easily add new mappings and even define your object mappings on execution time (being able to chose between multiple versions of your backend system).

Check it out!

You will find Motis category on NSObject for KVC object mapping in the GitHub repository of Mobile Jazz. Also, you can include it directly using CocoaPods in your projects.

GitHub: https://github.com/mobilejazz/Motis
CocoaPods: pod 'Motis', '~> 0.1.0'

References

Read the comments
Joan Martin
Starting with a mathematics degree, continuing with a computer science master's degree and working on mobile development during the past 10 years, Joan is a proficient software engineer. Motivated by great projects and an awesome team, Joan is currently leading the mobile team at Mobile Jazz and enjoying the MJ philosophy at its best.

Want to receive more insightful articles like this? Subscribe here.


By submitting your information you agree to our Privacy Policy