Demystifying JSON from web to Objects, without external dependencies!
Firstly, let me clear some points which I’ve been asked some times while chatting about this topic.
What do I mean when I say without dependencies?
Well, I mean about being able to find a solution using only the power and tools given by the iOS kit itself, without the need to inject any third party framework, like the cool ones we usually add using CocoaPods and Carthage.
So, is a bad practice make use of these external tools?
Yes and no. I’ll explain:
No, when you are doing it to prevent yourself to spend a lot of effort and time on doing code you already know about it, and is using the right code to solve a particular problem. This will produce fast and quality results on most cases, if done right, of course.
Yes. When the use of external frameworks is preventing you from being a developer who knows the platform he is working on, this becomes a really bad choice. When you go for third party libraries as the first option for any solution in any case, this is the situation where all the benefits will be turned into a trap on your developer knowledge and performance.
Once again, don’t get me wrong. I’m really proud to have Alamofire, Realm and other cool libraries on my projects. My point is just about when and how they should be applied.
When third party frameworks are cool?
- When you know you could solve the problem without them (indeed!);
- The chosen framework is not a black-box for you. I mean, you know what the library is doing and what resources is being used;
- The library will really solve your problem, not expand it;
- The library will speed up your solution;
- When the library deals with a specific case, which you not want to learn or spend time on. eg.: Bluetooth.
When you should NOT go for them?
- When you have no idea on what is going on and how you could deal with the problem with iOS native frameworks (you should at least have a basic idea about it);
- A lot of files and code will be injected on your project just for a small peace of code really been used;
- When it’s about a common workflow on iOS and you don’t know how to solve it by yourself, like load JSON from web and parse it. This is the case we will be exploring later.
Comparing in practice:
Also, relying on a external source can lead to a bad experience on critical events, like iOS updates. For instance, from swift 1.2 to 2.0, many coders dropped the support for iOS 7.1 on their frameworks, making a huge impact on refactoring task on large projects where they are present and still need to support versions below 8.0 of iOS.
Well, all this text is just to defend this point of view: the developer has to engage with the platform and know how to handle it with the tools it provides. This will lead to consistence on results and developer performance. Rely on a third party library must be to get things done in a fast and assertive way, it should never to hide knowledge opportunities or act as a black-box about the solution they provide.
the developer has to engage with the platform and know how to handle it with the tools it provides.
Rely on a third party library must be to get things done in a fast and assertive way, it should never to hide knowledge opportunities or act as a black-box about the solution they provide.
A Good case (or not) for going with external dependencies: Local Databases
If you ever tried to deal with local databases, you know how much it can be a problematic and time consuming task, even when using CoreData or Sqlite wrappers, for example. Databases are allways a heavy and complex task. So, why not go direct for Realm and make it easy for you? Seriously, if you never tried, you should taste it. I can’t imagine how it could be more simple and fast as this tool. Here’s an example from their site:
Maybe (or maybe not) a case for external dependencies: Auto Layout
How about doing Auto Layout in code? Simple task, lot of code to deal with. So, if you will do it a lot, I suggest you to write your own wrapper or take a shot at PureLayout. This is a great library which saves me from thinking about constrains when dealing with complex layouts, like ecommerce collectionView cells. For example, this is what you will code to center a view:
Easy, isn’t it? But if you are going to use this once in a while, why not write your own extension (to center your view in it’s superview, for example). After all, as a good programmer, even going for PureLayout, you should know how to do it yourself. Here’s how you could achieve it:
Now the classic case: load and parse JSON from web
Let’s explore a classic case now, which is part of many job tests for iOs developers around the world. Surprisingly, this is one thing that freezes many iOS folks out there as soon as they see an instruction like this: you should not use third party frameworks on this operation. Then, what should be considered an easy task, ends the new job opportunity for too many people, as the seniors developers take triggers like this to see how far the candidate is from the basic core of the platform.
So, what we need for this?
The whole process is really simple. We basic just need to rely on
NSJSONSerialization and some code around them. So let's see how we can do it.
Here’s how we can do a simple url loading (async):
and to parse the JSON into your array of User:
Believe me, this is what we need to accomplish the basic task. What we will do now is add some code without add complexity. The main goal is try to keep things a little more generics and handle errors, making it more reusable.
Part 1: the User Struct, to be mapped
We need an object to be mapped. Also, this object should be able to be initalized with a json.
Note that if the json doesn’t came with any required key, the User will not be valid. If you have a case where a var should not be mandatory, you just need to move it out from the guard block and this will be ok ;)
Part 2: the load
Firstly, let’s make an enum to make our error handle more friendly.
Now we improve our request putting it inside a
func and using a callback to return data or error for us:
switch extends our code a bit, but what we did here is simple: whenever we failed to get an OK status from the server (
statusCode == 200, for instance), we report the error in that case. If we got a success on request, we return the serialized data on the callback so another part of the code can parse it.
Part 3: the magic, json to array of User with one line!
Now we have the users JSON pulled from the web. Remember, for Swift, this is nothing more than an array of dictionaries, so…Just pass it to an Array magic command called flatMap! Here is how we do it:
I can see you smiling now, and thinking I’m crazy, maybe. But this is all you need to load and parse json from web, into a solid array of data. so, let’s make use of getUsersFrom to see our closure in action:
Now you believe me? Well, there will be a Playground file at the end for most stone hearts!
Bonus: the dump command is an alternative to print. In fact I’m using it here just for fun. I know most people never heard about it!
Swift is about protocols too, isn’t? So let see how we can turn our User initialization into a protocol which could be used for more objects later.
We start creating a protocol
JSONParselable and defining a func to be implemented on parseable objects.
Now, it’s a matter of implement this protocol on parseable objects, and we do it on an extension again to keep thins clear about responsibilities.
Remember, the implementation of model parse, should returns a valid User only if the essencial data is valid (found on JSON):
Now we can collect the users using the protocol implementation on User, just doing this:
Almost no difference from doing it on a custom init. But now you can spread the protocol to other objects. In fact, at this level this is only a matter of personal preference ;)
If you have many objects, just make sure they conforms to JSONParselable implementing the
withJSON func on each object. Don't forget that the data returned for each object on json data can be different. So, the Generics could me considered on this logic.
Don’t forget to check the Playground file for this article here
I tried to be practical and didactic on this article. Is not my intention to define the better or more accurate code, neither a ready solution, cause this is your job!
But if I can, here’s my advise: try to avoid to turn your project into a dependencies salad. Have faith on you too! And when using third-party libraries, use it wisely and consider the pros and cons about their applications and impact on your work.
All the best and until next time :)