Parsing JSON in Swift 4 using Decodable Protocol. Parsing a complicate JSON is difficult because of redoing whole process again and again. In swift 4 it's not like swift 2,3, parsing became super easy and fast by just using single line of code. In this tutorial we are diving into Decodable protocol for JSON Parsing.
Getting Started:
Create new project -> open Xcode -> File -> New -> Project -> Single View App, then tap next button. Type product name as 'JSONParseSwift4' then tap next and select the folder to save project.In this article we will discuss about struct. Structs are very helpful for storing heterogeneous data unlike Array. For example in struct we can store Int, String etc
Creating a simple Struct. Write the following struct next to 'import UIKit'.
struct Tutorials {
let id : Int
let name : String
let link : String
let imageUrl : String
}
let myTutorial = Tutorials(id: 1, name: "my tutorial", link: "some link", imageUrl: "some image")
print(myTutorial)
First thing we need sample JSON for parsing. So we need sample url for that. This is our sample url :
https://gist.githubusercontent.com/iosRevisited/bf28f444c262591b1807949ff40a2222/raw/695b2de9bc364762377d64595bf2b25a8de69786/sample.json
Now how to get data from that url?
Here we go with simple code using URLSession with completion handler. Here is code for getting data from url. Delete all code inside viewDidLoad() method and replace with following code.
let urlString = "https://gist.githubusercontent.com/iosRevisited/bf28f444c262591b1807949ff40a2222/raw/695b2de9bc364762377d64595bf2b25a8de69786/sample.json"
guard let url = URL(string: urlString) else {
return
}
URLSession.shared.dataTask(with: url) { (data, response, err) in
guard let data = data else { return }
// Old School method for parsing Swift 2/3/Objective-C
do {
let json = try JSONSerialization.jsonObject(with: data, options: .mutableContainers)
print(json)
} catch let jsonErr {
print("error in parsing",jsonErr)
}
}.resume()
Now store the data in struct. So need to initialize with dictionary. Replace old Struct with new Struct.
struct Tutorials {
let id : Int
let name : String
let link : String
let imageUrl : String
init(json:[String: Any]) {
id = json["id"] as? Int ?? 0
name = json["name"] as? String ?? ""
link = json["link"] as? String ?? ""
imageUrl = json["imageUrl"] as? String ?? ""
}
}
let tutorial = Tutorials(json: json)
print(tutorial.name)
Up to now what we did is old methods we used in Swift 2/3/Objective-C.
Now step into the new method introduced by apple in iOS 11 is Decodable Protocol. Remove init method in structure and provide Decodable Protocol to struct.
Replace structure with new struct with protocol.
struct Tutorial: Decodable {
let id : Int
let name : String
let link : String
let imageUrl : String
}
let tutorial = try JSONDecoder().decode(Tutorial.self, from: data)
print(tutorial.name)
Important - we should match the data keys with the structure properties.
Array of Dictionaries :
Now let see this JSON:
[
{
"id": 1,
"name": "Face Detection",
"link": "http://iosrevisited.blogspot.com/2017/08/face-detection-using-vision-framework.html",
"imageUrl": "https://support.apple.com/library/content/dam/edam/applecare/images/en_US/iOS/move-to-ios-icon.png"
},
{
"id": 2,
"name": "Real Time Object Detection",
"link": "http://iosrevisited.blogspot.com/2017/08/real-time-camera-object-detection-with.html",
"imageUrl": "https://support.apple.com/library/content/dam/edam/applecare/images/en_US/iOS/move-to-ios-icon.png"
}
]
Change url to https://gist.githubusercontent.com/iosRevisited/7e6cd23e2a267a2503698411a834fe6c/raw/890f5842181369b83c820b4a6702b42776a9aabf/tutorials.json
Replace old url with new url. Then it looks like this.
let urlString = "https://gist.githubusercontent.com/iosRevisited/7e6cd23e2a267a2503698411a834fe6c/raw/890f5842181369b83c820b4a6702b42776a9aabf/tutorials.json"
let tutorials = try JSONDecoder().decode([Tutorial].self, from: data)
print("\(tutorials)")
Great, array of dictionaries also parsed using decodable protocol.
Complex Data Parsing:
Now we will parse the following data from url - https://gist.githubusercontent.com/iosRevisited/65fff3a78a684909a7b64761799a02d3/raw/0850d72db8315ff25d2a24219d6592fd404deb35/Complex.json
{
"name": "iOS Revisited",
"description": "Blog about,Objective c language and Swift language programming questions, Tutorials, Bugs solving ....",
"tutorials": [
{
"id": 1,
"name": "Face Detection",
"link": "http://iosrevisited.blogspot.com/2017/08/face-detection-using-vision-framework.html",
"imageUrl": "https://support.apple.com/library/content/dam/edam/applecare/images/en_US/iOS/move-to-ios-icon.png"
},
{
"id": 2,
"name": "Real Time Object Detection",
"link": "http://iosrevisited.blogspot.com/2017/08/real-time-camera-object-detection-with.html",
"imageUrl": "https://support.apple.com/library/content/dam/edam/applecare/images/en_US/iOS/move-to-ios-icon.png"
}
]
}
struct siteDescription: Decodable {
let name: String
let description: String
let tutorials: [Tutorial]
}
Now change urString. It looks like following.
let urlString = "https://gist.githubusercontent.com/iosRevisited/65fff3a78a684909a7b64761799a02d3/raw/0850d72db8315ff25d2a24219d6592fd404deb35/Complex.json"
let siteData = try JSONDecoder().decode(SiteDescription.self, from: data)
print("\nname = \(siteData.name)")
print("\ndescription = \(siteData.description)")
print("\ntutorials = \(siteData.tutorials)")
Build and Run , we will see following as output in console.
Cool, we parsed data easily in a efficient way using Decodable Protocol.
import UIKit
ReplyDeletestruct detail : Decodable {
let id: Int
let name: String
let tel: String
let address: String
let longitude: Float
let latitude: Float
}
struct Scenics : Decodable {
let result: String
let message: String
let recordset: [detail]
}
class ViewController: UIViewController {
var countries = [Country]()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
let jsonURL = "http://research.cumi.co/scenics.php"
let url = URL(string: jsonURL)
URLSession.shared.dataTask(with: url!) { (data, response, error) in
guard let data = data else {return}
do {
let scenics = try JSONDecoder().decode(Scenics.self, from: data)
print(scenics.message)
}
catch {
print("error")
}
}.resume()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
Hi, above is my code.
But always error at runtime.
how to fix it?
Thanks Advances