Reading a JSON file using Swift


In this article, we will see some examples of how we can read the JSON file using JSONSerialization and JSONDecoder classes. Nowadays, these classes are used in most iOS applications to work with JSON files.

You can use the JSONSerialization class to read the JSON file in the Swift language. In order to read a json file, first you will require to convert it into a string or data object. After that, you can pass the string or data object to JSONSerialization class to convert it into a dictionary or array object.

JSONSerialization

The Foundation framework for iOS and macOS includes a JSONSerialization class by default. To create a Swift dictionary or array, this class needs a string or data object. Using the same class, you can also turn a dictionary or an array into a JSON object. The serialization and deserialization procedures are handled by the JSONSerialization class.

The main function of this class, jsonObject(with:options:), is used to deserialize, or turn JSON data into Swift objects. This method requires a data object that has JSON data as well as an argument named options that regulates the method's behavior. A Swift object, which can either be an array or a dictionary, is returned by this method. The JSON data format will determine the return type.

Here is an example of how to read a JSON file and parse it into a dictionary −

Reading JSON using the JSONSerialization class

Here is the sample JSON −

Example

{
   "id": 1,
   "title": "iPhone 12",
   "price": 749,
   "thumbnail": "https://i.dummyjson.com/data/products/1/thumbnail.jpg",
   "manufacturedDetail": {
      "company": {
         "manufacturedBy": "Apple Inc."
      }
   }
}

We will use the above JSON to read it. You can add a new file to the Xcode project with the extension ".json" format by giving any name to the file.

Reading JSON file

func readJSONFile(forName name: String) {
   do {
      if let bundlePath = Bundle.main.path(forResource: name, ofType: "json"),
      let jsonData = try String(contentsOfFile: bundlePath).data(using: .utf8) {           
         if let json = try JSONSerialization.jsonObject(with: jsonData, options: .mutableLeaves) as? [String: Any] {
            print("JSON: \(json)")
         } else {
            print("Given JSON is not a valid dictionary object.")
         }
      }
   } catch {
      print(error)
   }
}

Output

JSON: ["title": iPhone 12, "price": 749, "thumbnail": https://i.dummyjson.com/data/products/1/thumbnail.jpg, "id": 1, "manufacturedDetail": {
   company =     {
      manufacturedBy = "Apple Inc.";
   };
}]

This will give you a JSON object that you can use as a dictionary in your code. If your JSON file is an array of objects, you can use the mutableContainers option instead of mutableLeaves. As we have to read a dictionary from the JSON object, we will use the mutableLeaves option.

Reading JSON using the JSONDecoder() class

The new version of Swift introduced the Codable protocol which makes it much easier and more flexible to use.

The JSONDecoder class is then used to parse the JSON data from the file into an instance of the given Type either a class or structure. The decode(_:from:) method is used to deserialize the JSON data, and the resulting Type object is then returned to access the properties of the Type object.

We are attempting to read the same JSON given above as an example using the Codable protocol. Before we are ready to decode the JSON data using the JSONDecoder() class, let's prepare the model class to be provided at the time of decoding.

Here is the model class according to the above JSON data −

import Foundation
struct Product: Decodable {  
   let id: Int
   let title: String
   let price: Int
   let thumbnail: String
   let manufacturedBy: String
    
   enum RootKeys: String, CodingKey {
      case id, title, price, thumbnail, manufacturedDetail
   }
    
   enum ManufacturedKeys: String, CodingKey {
      case company
   }
    
   enum CompanyKeys: String, CodingKey {
      case manufacturedBy
   }
   
   init(from decoder: Decoder) throws {
      let values = try decoder.container(keyedBy: RootKeys.self)
      id = try values.decode(Int.self, forKey: .id)
      title = try values.decode(String.self, forKey: .title)
      price = try values.decode(Int.self, forKey: .price)
      thumbnail = try values.decode(String.self, forKey: .thumbnail)
        
      let manufacturedContainer = try values.nestedContainer(keyedBy: ManufacturedKeys.self, forKey: .manufacturedDetail)
      let companyContainer = try manufacturedContainer.nestedContainer(keyedBy: CompanyKeys.self, forKey: .company)
      self.manufacturedBy = try companyContainer.decode(String.self, forKey: .manufacturedBy)
   }
}

How to decode?

func readJSONFile(forName name: String) {
   do {  
   
      // creating a path from the main bundle and getting data object from the path
      if let bundlePath = Bundle.main.path(forResource: name, ofType: "json"),
      let jsonData = try String(contentsOfFile: bundlePath).data(using: .utf8) {
            
         // Decoding the Product type from JSON data using JSONDecoder() class.
         let product = try JSONDecoder().decode(Product.self, from: jsonData)
         print("Product name: \(product.title) and its price: \(product.price)")
      }
   } catch {
      print(error)
   }
}

Output

Product name: iPhone 12 and its price: 749

Conclusion

In Swift, you are able to convert raw JSON data into collections like arrays or dictionaries via a low-level API. You can use the JSONSerialization class to convert the raw JSON object into meaningful objects. This class is in-built into the Foundation framework. You can use this class on any platform such as iOS, macOS, watchOS, etc. Also, in reverse order, you can convert back the custom objects into raw JSON data using the deserialization process.

In Swift 4, Apple introduced the Codable protocol which makes the serialization and deserialization process easy. This protocol provides a flexible way to use JSON data to parse and store the data into model class/struct. This protocol can be used to convert the model object into JSON data easily.

The Codable protocol helps to reduce the code and handle the process of serialization and deserialization, making the code more concise and maintainable.

Updated on: 28-Feb-2023

8K+ Views

Kickstart Your Career

Get certified by completing the course

Get Started
Advertisements