Handling data is a common task for frontend developers, and the data is very often in JSON format. SwiftyJSON is an open source third-party library that is useful for handling JSON data easily in Swift. As of this writing, the package has 21K+ stars on GitHub and has been maintained since its initial release in 2014. It supports the latest versions of Swift, Xcode, and iOS. So far, it has met all my needs.
In this article, we’ll review how to handle JSON data easily in Swift with SwiftyJSON. We’ll use a demo project with a macOS command line interface to walk through the tutorial.
For the examples used in this article, we’ll use Swift v5, Xcode v13.2.1, and SwiftyJSON v5.0.1.
Let’s get started!
Since a user interface is not important for this project, we’ll create and use a macOS command line tool. To create a CLI for macOS, open Xcode and click on Create a new Xcode project. Next, under macOS, select Command Line Tool, then click Next, and follow the remaining instructions.
I like Pokémon, so I’ve decided to use it as the project’s topic. In this project, we’ll use the RESTful Pokemon API. We’ll request data for the character, Charmander, by fetching this JSON: https://pokeapi.co/api/v2/pokemon/charmander.
This article will focus on handling JSON, so we’ll skip over the process of requesting the JSON data.
For this demo, I’ve used the macOS URLSession to handle the HTTP requests, but you may also use Alamofire or Moya. In addition, you can always access the code in my GitHub repository. After we get the data, we’ll request some of Charmander’s attributes (for example, name, abilities, and type) and then we’ll display them in the terminal output.
The terminal output will look like this:
Let’s get started.
To use a third-party library, we need to import that package in our project. Therefore, our first step is to add the SwiftyJSON package to our project; we’ll use the Swift Package Manager.
Here’s our path: Xcode > ( Xcode project name) > Targets > (Xcode project name).
In the General tab, under the Frameworks and Libraries dropdown, we click on + and select Add package dependency. Then, we enter the package Git URL: https://github.com/SwiftyJSON/SwiftyJSON.git.
After the package is successfully added, we’ll see SwiftyJSON listed under Framework, as well as under Package Dependencies in the Project Navigator:
Now, we’re ready to write some code. To start, we’ll use a snippet from our JSON data:
"name": "charmander", "order": 5, "past_types": [], ...
We’ll create a JSON object that includes the name
attribute of the data. Then, we’ll create a function to get the name
attribute so that we can access it:
func getName(data: Data) { if let json = try? JSON(data: data) { let name = json["name"].string ?? "N/A" print("Name: \(name)") } }
When we call the getName
function, we get the following output:
Name: charmander
Now, let’s work with the nested JSON from our Charmander HTTP request:
"abilities": [ { "ability": { "name": "blaze", "url": "<https://pokeapi.co/api/v2/ability/66/>" }, "is_hidden": false, "slot": 1 }, { "ability": { "name": "solar-power", "url": "<https://pokeapi.co/api/v2/ability/94/>" }, "is_hidden": true, "slot": 3 } ], {...}
We’ll create a function to get the abilities
attribute from the Charmander data. Previously, we created a JSON object, but now we have an array of objects. We’ll need to trace through the abilities
array and get the name
attribute of each ability
.
func getAbilities(data: Data) { if let json = try? JSON(data: data) { for (_, abilities) in json["abilities"] { let ability = abilities\["ability"\]["name"].string ?? "N/A" print("Ability: \(ability)") } } }
When we call the getAbilities
function, we get the following output:
Ability: blaze
Ability: solar-power
Similar to abilities
, we also have the types
attribute. Then, inside the object, we have a type
object with a name
attribute. We can see both attributes in the below JSON snippet:
"types": [ { "slot": 1, "type": { "name": "fire", "url": "https://pokeapi.co/api/v2/type/10/" } } ]
Now, we’ll trace through the types
array and get the name
attribute of each type
.
func getType(data: Data) { if let json = try? JSON(data: data) { for (_, types) in json["types"] { let type = types\["type"\]["name"].string ?? "N/A" print("Type: \(type)") } } }
When we call the getType
function, we get the following output:
Type: fire
In Swift, we have to use explicit typing. The benefit to this is that we are less likely to make mistakes. The downside is that it is not very flexible.
For example, when we fetch JSON data, we create the attributes by declaring their data type. If the data type changes from the server side, we’ll be unable to parse the JSON data and the app will crash. Fortunately, SwiftyJSON helps us address this issue.
Let’s look at an example.
In the below code snippet, we specify that the data type is a string
. We could also specify that it must be an integer; the point here is that the code indicates it must be of the type we are specifying.
let ability = abilities\["ability"\]["name"].string!
In this example, as long as the data type actually is a string
, everything is fine. But if the data type changes, the value becomes nil and the app will crash.
Now, let’s look at the same example, but this time we’ll use a nil
-coalescing operator to accomodate any possible changes in data type:
let ability = abilities\["ability"\]["name"].string ?? "N/A"
In the above snippet, we check to see if the data type is a string
. If it is not a string
, the value “N/A” is returned. The app does not crash. Of course, you are not limited to “N/A”, you may use any designation you like.
In this article, we reviewed how to handle JSON in Swift with SwiftyJSON and discussed how to handle type issues. We walked through the article examples using a demo with a macOS command line interface.
I hope you’ve enjoyed this article. Go to GitHub to check out the sample project that I made for this article. Feel free to reach out to me at [email protected] or in the below comment section. I appreciate your valuable feedback. Take care! ✨
Install LogRocket via npm or script tag. LogRocket.init()
must be called client-side, not
server-side
$ npm i --save logrocket // Code: import LogRocket from 'logrocket'; LogRocket.init('app/id');
// Add to your HTML: <script src="https://cdn.lr-ingest.com/LogRocket.min.js"></script> <script>window.LogRocket && window.LogRocket.init('app/id');</script>
Would you be interested in joining LogRocket's developer community?
Join LogRocket’s Content Advisory Board. You’ll help inform the type of content we create and get access to exclusive meetups, social accreditation, and swag.
Sign up nowBuild scalable admin dashboards with Filament and Laravel using Form Builder, Notifications, and Actions for clean, interactive panels.
Break down the parts of a URL and explore APIs for working with them in JavaScript, parsing them, building query strings, checking their validity, etc.
In this guide, explore lazy loading and error loading as two techniques for fetching data in React apps.
Deno is a popular JavaScript runtime, and it recently launched version 2.0 with several new features, bug fixes, and improvements […]