Codable vs ObjectMapper

James Ruston
You Don’t Know Swift
4 min readOct 12, 2017
Photo by https://unsplash.com/photos/_rNVw54xZZg

I’ve recently been experimenting with Swift’s new Codable protocol as a way to map JSON fetched from a remote service into a Swift model object.

For a bit of background, Codable was added in Swift 4 as a way to cleanly allow objects to convert themselves into and out of an external representation. Codable itself is just a typealias of Decodable and Encodable.

For this post I’m going to be focusing on the Decodable part, as it’s the conversion from a remote JSON representation that I’m interested in.

Comparison

I’ve used ObjectMapper extensively in the past but as Codable is now built into Swift I wanted to do a comparison of the two. The features that I’m wanting to compare are:

  • Validation 🕵️
  • Custom Transformation (mapping into custom types, e.g. mapping a JSON string into a regex) 🤖
  • Error handling ⚠️

The data I’m going to parse is real config we fetch remotely for the BBC Sport app

It’s a fairly simple JSON structure but it’s got a couple of Regular Expressions in that I’d like to be mapped to NSRegularExpression, not a String

ObjectMapper

The structs required to map this JSON model with ObjectMapper are as follows.

The stucts all conform to the ImmutableMappable protocol, which means they need a constructor that takes a Map object and throws an error if the mapping fails.

Validation

To perform validation you can make use of Optionals. In this example we’ve decided the app can function without these email addresses so the emails are optional. map.values("emails") throws an error if they key isn’t present or it cannot be cast to the correct type. We make use of try? to capture that error and just turn it into a nil value if there’s an error.

If we decide a particular property is required then we don’t mark it as optional and allow the error to propagate.

Overall the validation is very straight forward using ImmutableMappable

You might have noticed there’s an additional argument passed into this call map.value(“regex”, using: RegexTransformer()) That’s for the custom transformation to turn the String into a NSRegularExpression which leads my nicely on to my next point!

Custom Transformation

ObjectMapper supports custom transformations out of the box, and it’s very straight forward.

Here we’re just implementing the TransformType protocol and the associated transformFromJSON method. That takes in a type and which we cast to String and then safely try? to convert the String to an NSRegularExpression .

This transformer is then available to reuse anywhere 👍🏻

Error Handling

To test the error handling I’ll be using a JSON file with the missing output key.

When running this through ObjectMapper we get a nice helpful error message out.

Got an error while mapping.
- reason: Cannot cast to 'String'
- location: Config.init(map:):30
- key: output
- currentValue: nil

It tells us everything we need to quickly find where the issue is. I have found when using the AlamofireObjectMapper integration the errors get suppressed which is less than ideal.

Codable

Out of the box the equivalent Codable implementation is as follows

It’s very similar to ObjectMapper although the keys are defined as enums using the CodingKey protocol.

There’s a really nice feature using Codable in that the initialiser can be generated for you if they enum cases are equal to the property, and the type that we’re mapping to is itself Decodable An example of that is CodableConfig above. Since all it’s properties are themselves Decodable we don’t need to write an initialiser! 🙌🏻

Validation

This works exactly the same as ObjectMapper

The initialiser throws an error if there’s an error mapping, which can be handled at the call site. Again, make good use of Optionals here to decide how best to handle errors.

Custom Transformation

You will notice in the above code, it all gets a bit less clear when we are trying to map to our NSRegularExpression type. We suddenly have to implement the initialiser init(from decoder: Decoder) and get ourselves a KeyedDecodingContainer from the Decoder

There’s a great writeup about this already if you’d like more detail, which I’m not going to go over here.

The code becomes quite verbose to write now, and we’re repeating the transformation code. That’s only an extra line in this case but there are frequently times when I want to write more complex transformations that I’d like to isolate like I can with ObjectMapper

So I made a small library to add support for custom transformations 🎉 this is available through CocoaPods, or you could just copy the source in since it’s just a couple of files.

You might think of adding an extension to the type that you don’t own but there’s a good explanation of why this isn’t possible on Swift Evolution.

Using the CodableExtensions library we can now simplify our code to look very similar to ObjectMapper

And the RegexCodableTransformer also is very similar to what we previously had with ObjectMapper

The library also simplifies the interface to container.decode() so the type no longer needs to be passed in as it’s inferred.

Error Handling

I’m using the same JSON file to compare error handing as before. The error looks like

keyNotFound(config_spike.CodableRewriter.(CodingKeys in _4D474241C6D85B5C48988D77CA644850).output, Swift.DecodingError.Context(codingPath: [config_spike.CodableConfig.(CodingKeys in _4D474241C6D85B5C48988D77CA644850).rewriter], debugDescription: "No value associated with key output (\"output\").", underlyingError: nil))

The error isn’t quite as pretty looking 💅🏻 but it’s got everything to debug the issue.

Conclusion

There are far more similarities than differences between the two approaches. If transformations are important then ObjectMapper works out of the box. However, one of the main motivators for switching is moving to the standard that Apple have created without having to bring in another library.

If transformations are important, by adding a couple of protocols, you can get the same behaviour with Codable

We’ve decided to move to Codable now for all our new features going forwards. I’m sure there’s features I’ve missed off this list but I picked the most important ones for us.

--

--