How to parse JSON with Swift 3

Why is it so hard to parse JSON in Swift?

I can’t count the number of times I’ve seen or heard this question since Swift came out. So what’s the problem? Shouldn’t a real programming language make it super simple to work with JSON since everyone uses it everywhere?

The issue is that we’re taking weakly-typed JSON data and transforming it into strongly-typed Swift. Any number of things could go wrong, such as:

  • the JSON is just completely invalid (missing an opening brace, a closing brace, a comma, quotation marks, or something else)
  • you expect an integer in the JSON but get a string (or you expect a boolean and get an integer, or whatever…)
  • one of the values in the JSON is null
  • the structure of the JSON is different from what you expect

Swift can handle all of this just fine, but since it’s strongly typed, you need to think about these things before it compiles, rather than waiting until runtime for your app to crash. That’s a tradeoff I’m happy to make, and I’m sure the people who use my apps appreciate it, too.

We’ll look at how to parse a JSON array that we could use to display a list of items in a table view. More specifically, we’ll use the following JSON to display a list of blog titles in our app.

Assuming we’ve made a request and received the JSON above, we just need to ask JSONSerialization to give us a JSON object, and then pull out the “blogs” and “name” keys. First, let’s take a look at the full code, then we’ll break it down and explain it in smaller pieces:

This gives us the following output:

Now let’s break down what’s actually happening here.

First of all, the JSONSerialization code is in a do/catch block since jsonObject(with:) may throw an error. If you’re familiar with Objective-C, you’ll notice that we don’t pass in an NSError pointer here – instead, jsonObject(with:) is marked with throws in Swift, meaning it may throw an error. The error that we catch (which is called error by default) replaces the NSError pointer from Objective-C.

Let’s look at the first line of the conditional:

What in the world is that? I know, it’s weird.

We’re unwrapping the optional data — the second data in the statement, whose type is Data?. Then we’re setting it equal to a new constant called data in the first half of the statement(let data = …). This will look strange to you for maybe a few days, weeks, or months, but that’s totally normal. Just understand that it’s a way to go from a Data? type (optional Data) to a non-optional Data, keeping the same variable name. (This strange if let syntax is called optional binding, and you need to understand it if you’re writing Swift. You can learn more about it — and about optionals in general — in the free 5-Part Guide to Swift.)

Moving on:

Now, we’re attempting to serialize the JSON data into an object using JSONSerialization.jsonObject(with:) and cast that to a dictionary with String keys and Any values. And the result of all that is assigned to a constant called json. Next…

Here, we’re taking the "blogs" from the JSON, casting that value to an array of dictionaries ([[String: Any]]), and assigning it to a constant called blogs.

Assuming all of those let statements are successful, our if block will execute.

And finally we get to our loop which should look relatively familiar:

Here, we’re iterating through our array of blogs, and we know that blog is a dictionary of type [String: Any] based on the type of our blogs array. Inside the for loop, we’re doing optional binding again to grab the name of the blog as a String, then appending it to our names array.

Conclusion

I hope this helps you to start working with JSON in Swift 3 — and furthermore, I hope you see that it’s relatively simple to do using the JSONSerialization class from the built-in Foundation framework. So many people seem to want grab a third-party library to parse JSON, but for most use cases, I see very little benefit to using one to do something so simple. You don’t need a third-party library for everything.

If you want to take your JSON parsing further, I’d suggest creating model objects to represent your data, mapping your JSON to those (instead of using dictionaries everywhere), and adding some unit tests to make sure your parsing and mapping code works the way you want it to. You can learn more about those with Parsing JSON in Swift, which is 20% off for the Swift 3 launch through today — December 16, 2016 — at 1:00 PM Eastern. Build confidence in your parser today by writing tests with Parsing JSON in Swift.