iOS Swift JSON Parsing Tutorial

In this tutorial, we will learn how to parse a JSON response in our iOS Application using Swift. We will display the parsed response in a UITableView. To know more about UITableView, check outthis tutorial before proceeding ahead.

Swift JSON Parsing

JSON is the most commonly used format to send and receive data from the web services. The data is in the form of key-value pairs. UsingSwift Dictionaries we can easily fetch the values from the keys.

In this tutorial, we’ll be parsing JSON data from a local resource file.

The JSONSerialization class is used to parse a JSON data into a dictionary of key-value pairs by converting the Data object.

The type of a JSON data is [String: Any] .

Let’s create a single view iOS Application in which we’ll parse the data from a locally created JSON file into the TableView.

iOS JSON Parsing Example Project Structure

iOS Swift JSON Parsing Tutorial
iOS Swift JSON Parsing Tutorial

In the Main.storyboard we’ve added a label and a TableView to our ViewController.

iOS Swift JSON Parsing Tutorial
iOS Swift JSON Parsing Tutorial

We’ve set the TableView delegates to the ViewController.

For more info on how to set up a TableView using Storyboard, referthis tutorial.

Swift JSON Parsing Code

We will be parsing JSON data from the file. The response.json file looks like this:

iOS Swift JSON Parsing Tutorial
iOS Swift JSON Parsing Tutorial

Serialising the data

let url = Bundle.main.url(forResource: "response", withExtension: "json")
        
guard let jsonData = url else{return}
guard let data = try? Data(contentsOf: jsonData) else { return }
guard let json = try? JSONSerialization.jsonObject(with: data, options: []) else{return}

In the above code, we fetch the file over the Bundle.main.url instance.

The Data instance converts it into a Data format which is then serialized as JSON.

Fetching data from the JSON instance

Now that we’ve got the JSON instance, we can fetch the data in the following manner:

if let dictionary = json as? [String: Any] {
            
            if let title = dictionary["title"] as? String {
             labelHeader.text = title
            }
            
            if let year = dictionary["year"] as? Double {
                print("Year is \(year)")
            }
            if let more_info = dictionary["more_info"] as? Double {
                //This doesn't get printed.
                print("More_info is \(more_info)")
            }
            
            for (key, value) in dictionary {
                print("Key is: \(key) and value is \(value)" )
            }
            
        }

In the TableView, we’ll populate another JSON file :

iOS Swift JSON Parsing Tutorial
iOS Swift JSON Parsing Tutorial

ViewController.swift

import UIKit

class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {

    @IBOutlet weak var labelHeader: UILabel!
    @IBOutlet weak var tableView: UITableView!
    

    var movieList = [MarvelData]()
    
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        
        let url = Bundle.main.url(forResource: "response", withExtension: "json")
        
        guard let jsonData = url
            else{
                print("data not found")
                return
        }
        
        guard let data = try? Data(contentsOf: jsonData) else { return }
    
        guard let json = try? JSONSerialization.jsonObject(with: data, options: []) else{return}
        
        if let dictionary = json as? [String: Any] {
            
            if let title = dictionary["title"] as? String {
             labelHeader.text = title
            }
            
            if let year = dictionary["year"] as? Double {
                print("Year is \(year)")
            }
            if let more_info = dictionary["more_info"] as? Double {
                //This doesn't get printed.
                print("More_info is \(more_info)")
            }
            
            for (key, value) in dictionary {
                print("Key is: \(key) and value is \(value)" )
            }
            
        }
        
        //Now lets populate our TableView
        let newUrl = Bundle.main.url(forResource: "marvel", withExtension: "json")
        
        guard let j = newUrl
            else{
                print("data not found")
                return
        }
        
        guard let d = try? Data(contentsOf: j)
            else { print("failed")
                return
                
        }
        
        guard let rootJSON = try? JSONSerialization.jsonObject(with: d, options: [])
            else{ print("failedh")
                return
                
        }
        
        if let JSON = rootJSON as? [String: Any] {
            labelHeader.text = JSON["title"] as? String
            
            guard let jsonArray = JSON["movies"] as? [[String: Any]] else {
                return
            }
            
            print(jsonArray)
            let name = jsonArray[0]["name"] as? String
            print(name ?? "NA")
            print(jsonArray.last!["year"] as? Int ?? 1970)
            
            for json in jsonArray
            {
                guard let movieName = json["name"] as? String else{ return }
                guard let movieYear = json["year"] as? Int else{ return }
                movieList.append(MarvelData(movieName: movieName, movieYear: movieYear))
            }
            
            self.tableView.reloadData()
            
        }
             
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
    
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return movieList.count
    }
    
    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let currentMovie = movieList[indexPath.row]
        let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as UITableViewCell
        cell.textLabel?.text = currentMovie.movieName
        cell.detailTextLabel?.text = "\(currentMovie.movieYear)"
        return cell
    }

}

struct MarvelData {
    
    let movieName: String
    let movieYear: Int
    
    public init(movieName: String, movieYear: Int) {
        self.movieName = movieName
        self.movieYear = movieYear
    }
}

In the above code, we’ve parsed the second json file as well and appended each of the JSON Array elements into the array which holds the structures.

To display this data we must call reloadData() over the tableView instance.

We can make the code that sets the json values in the structure instances much better.

struct MarvelData {
      var movieName: String
      var movieYear: Int
   init(_ dictionary: [String: Any]) {
      self.movieName = dictionary["name"] as? String ?? "NA"
      self.movieYear = dictionary["year"] as? Int ?? 1970
    }
}

Doing this we can change our :

guard let movieName = json["name"] as? String else{ return }
guard let movieYear = json["year"] as? Int else{ return }
movieList.append(MarvelData(movieName: movieName, movieYear: movieYear))

to

movieList.append(MarvelData(json))

Instead of iterating over the jsonArray using a for loop, we can easily use the handy operator concatMap in Swift. So this:

for json in jsonArray
{
    movieList.append(MarvelData(json))
}

Changes to

movieList = jsonArray.compactMap{return MarvelData($0)}
//or
movieList = jsonArray.compactMap{MarvelData($0)}
//or
movieList = jsonArray.compactMap(MarvelData.init)

This is the power of Swift!

The output of the above application in action is:

iOS Swift JSON Parsing Tutorial
iOS Swift JSON Parsing Tutorial

This brings an end to this tutorial. You can download the project from the link below.

iOSJsonParsing