Reading and Writing to a JSON in Swift

Lets consider you have a sample JSON as shown below
https://gist.github.com/kmdarshan/cfa6a940268f7091faf886ed63b3b559

You can make use of Codable Library (https://developer.apple.com/documentation/swift/codable) in Swift to read and write data from a JSON.

Firstly you need to map your data from the JSON onto a Struct as shown below. Once you have done that, its easy to read it using the decode and encode libraries in swift.

https://gist.github.com/kmdarshan/897f3e54ab4f133c25af4512be7e4ff1

Let’s consider you have the below JSON.

			[
				{
					"name": "red",
					"loan_amount": 1234
				},
				{
					"name": "flower",
					"loan_amount": 100
				},
				{
				 "name": "Inc",
				 "loan_amount": "100"
			 }
			]

It’s an array. Everything seems fine, until you notice that the loan_amount is a String and Int. This will fail to parse normally. You would need to go about this by parsing the individual key in the initializer as show below


struct StudentInfo : Codable {
	var name: String = ""
	var amount: Int = 0
	
	enum CodingKeys: String, CodingKey {
		case name
		case amount = "loan_amount"
	}
	
	init(from decoder: Decoder) throws {
		let container = try decoder.container(keyedBy: CodingKeys.self)
		name = try container.decode(String.self, forKey: .name)
		do {
			// first try to parse as a Int
			amount = try container.decode(Int.self, forKey: .amount)
		} catch {
			// Int parsing failed, lets parse it as a String
			let amountString = try container.decode(String.self, forKey: .amount)
			if let amountInt = Int(amountString) {
				amount = amountInt
			} else {
				throw error
			}
		}
	}
}
[learnjson.StudentInfo(name: "red", amount: 1234), learnjson.StudentInfo(name: "flower", amount: 100), learnjson.StudentInfo(name: "Inc", amount: 100)]

You will get the output as shown above.

Now let’s add more complication to the JSON. Let’s add a dictionary inside a dictionary. And add an array inside the dictionary.

			[
				{
					"name": "red",
					"loan_amount": 1234,
					"address" : {
						"street": "175 bay",
						"zip": 95134
					},
					"surnames": [
						"jagan",
						"hello",
						"dimmmer"
					]
				},
				{
					"name": "flower",
					"loan_amount": 100
				},
				{
				 "name": "Inc",
				 "loan_amount": "100",
				  "address" : {
					  "street": "175 bay",
					  "zip": 95134
				  }
				}
			]

You need to change the parsing in the decoder. First, you would need to create another codable called Address and then pass this to the StudentInfo codable struct. Then parse it in the init method.

struct Address: Codable {
	var street: String
	var zip: Int
}

struct StudentInfo : Codable {
	var name: String = ""
	var amount: Int = 0
	var address: Address
	var surnames: [String] = []
	
	enum CodingKeys: String, CodingKey {
		case name
		case amount = "loan_amount"
		case address
		case surnames
	}
	
	init(from decoder: Decoder) throws {
		let container = try decoder.container(keyedBy: CodingKeys.self)
		name = try container.decode(String.self, forKey: .name)
		do {
			// first try to parse as a Int
			amount = try container.decode(Int.self, forKey: .amount)
		} catch {
			// Int parsing failed, lets parse it as a String
			let amountString = try container.decode(String.self, forKey: .amount)
			if let amountInt = Int(amountString) {
				amount = amountInt
			} else {
				throw error
			}
		}
		
		do {
			address = try container.decode(Address.self, forKey: .address)
		} catch {
			address = Address(street: "", zip: 0)
		}
		
		do {
			surnames = try container.decode([String].self, forKey: .surnames)
		} catch {
			surnames = []
		}
	}
}

The output would be as shown below

[learnjson.StudentInfo(name: "red", amount: 1234, address: learnjson.Address(street: "175 bay", zip: 95134), surnames: ["jagan", "hello", "dimmmer"]), learnjson.StudentInfo(name: "flower", amount: 100, address: learnjson.Address(street: "", zip: 0), surnames: []), learnjson.StudentInfo(name: "Inc", amount: 100, address: learnjson.Address(street: "175 bay", zip: 95134), surnames: [])]

Leave a Reply

Your email address will not be published. Required fields are marked *