#5 JSON parsing in Swift

Xử lý JSON response với Codable Protocol trong Swift 4

JSON nói chung, chúng ta sử dụng để gửi và nhận dữ liệu từ hệ thống web. Chúng ta có thể sử dụng dễ dàng trong ứng dụng Swift của chúng ta. Hầu hết các ứng dụng hoàn toàn dựa vào JSON. Nếu ứng dụng của bạn đang giao tiếp với web service API sau đó nó sẽ gửi về  Dictionary(Object)ArrayStringBoolNumber. Chúng ta cần ghi nhớ trước khi tạo mới model class kiểu biến từ web service API trả về là gì. Dựa vào response đó chúng ta sẽ tạo Model class. Trong chủ đề này, sẽ bao gồm hầu hết các phần phân tích liên quan từ cơ bản đến cấp độ nâng cao.

Ban đầu, đó là một nhiệm vụ khó khăn đối với tôi khi hiểu phân tích cú pháp JSON. Sau đó, tôi nhận ra nó không là gì đối với tôi. Nó rất dễ sử dụng. Chỉ cần hiểu loại trả lời. Đó là điều chính. 🙂

 

Bắt đầu với Network Request, URLSession

Trước khi bắt đầu code chúng ta phải kiểm tra API trên browser.

1__-LSxa-trIRQHwae6UXV4g.png

 

Bây giờ chúng tôi đã nhận được response trong trình duyệt web, hãy viết code trong Xcode tạo dự án mới cho phân tích cú pháp JSON.

  • Thêm plist file trong project của bạn, open it as source

1_Zrvd_NLro2wP0WdTc8i5Wg.png

<key>NSAppTransportSecurity</key>
<dict>
  <key>NSAllowsArbitraryLoads</key>
  <true/>
</dict>
  • Bây giờ tạo Network request với URLSession cho web API

Chúng ta đang tạo ra request với web API đang xử lý dữ liệu và lỗi chúng sẽ tạo thành response. Tôi đang sử dụng ở đây là JSONSerialization xây dựng Foundation framework nó sẽ chuyển đổi dữ liệu JSON sang nền tảng object. 

Trong phần này, tôi đã sử dụng API thử nghiệm từ JSONPlaceholder.

guard let url = URL(string: ”https://jsonplaceholder.typicode.com/todos") else {return}
let task = URLSession.shared.dataTask(with: url) { (data, response, error) in
guard let dataResponse = data,
          error == nil else {
          print(error?.localizedDescription ?? "Response Error")
          return }  
    do{ 
        //here dataResponse received from a network request 
        let jsonResponse = try JSONSerialization.jsonObject(with: dataResponse, options: []) print(jsonResponse) //Response result } catch let parsingError { print("Error", parsingError) } } task.resume()
  • Response từ web API in JSON format trông như thế này. Bây giờ chúng ta cần lấy các values từ response. Ở đây response của chúng ta là một JSON array.
[
  {
    "userId": 1,
    "id": 1,
    "title": "delectus aut autem",
    "completed": false
  },
  {
    "userId": 1,
    "id": 2,
    "title": "quis ut nam facilis et officia qui",
    "completed": false
  }
]
  • Bây giờ xử lú với JSON response object
guard let jsonArray = jsonResponse as? [[String: Any]] else {
      return 
}
print(jsonArray)
//Now get title value 
guard let title = jsonArray[0]["title"] as? String else { return } print(title) // delectus aut autem

Chúng ta cố gắng in ra tất cả title keys values.

HIện tại, JSON response của chúng ta là một Array của Dictionary([[String: Any]]). Do vậy chúng ta đang lấy Dictionary từ mọi index của Array với sự trợ giúp của for – loop. Sau khi lấy được giá trị truy cập vào Dictionary từ các keys.

for dic in jsonArray{
    guard let title = dic["title"] as? String else { return }  
    print(title) //Output
}

Bây giờ chúng ta tạo User structure để xử lý dữ liệu. Trong response chúng ta đang lấy có các kiểu khác nhau của values Int, String, Boolean dựa vào các giá trị tôi chọn ở đây model structure của tôi để quản lý response.

struct User {
      var userId: Int
      var id: Int
      var title: String
      var completed: Bool
   init(_ dictionary: [String: Any]) {
      self.userId = dictionary["userId"] as? Int ?? 0
      self.id = dictionary["id"] as? Int ?? 0
      self.title = dictionary["title"] as? String ?? ""
      self.completed = dictionary["completed"] as? Bool ?? false
    }
}

Use Model để xử lý JSON response

var model = [User]() //Initialising Model Array
for dic in jsonArray{
    model.append(User(dic)) // adding now value in Model array
}
print(model[0].userId) // 1211

Bây giờ bạn biết vào thứ về JSON parsing đúng không? 😀

Chúng ta sẽ làm tương tự nhiều hơn Swifty với FlatMap

var model = [User]()
model = jsonArray.flatMap{ (dictionary) in
            return User(dictionary)
        }
print(model[0].userId)
//make more simple
model = jsonArray.flatMap{ return User($0)}
//One more time 
model = jsonArray.flatMap{User($0)}
//Or 
model = jsonArray.flatMap(User.init)
//Output
print(model[0].userId) // 1211

Codable Protocol

Điều này là một protocol được giới thiệu bởi Apple in Swift 4 có thế cung cấp Encodable và Decodable trong chức năng. Nó sẽ make JSON parsing dễ dàng hơn. Nó có thể chuyển đổi chính nó vào và ra khỏi một biểu diễn bên ngoài.

Codable model trông như thế này. Nó khá dễ để hiểu trong ít code chúng ta có thể quản lý được nó.

Đâu là Codable model ví dụ tôi thể hiện cho bạn ở đây. Bạn cần làm struct model của bạn dựa trên JSON response của bạn.

struct User: Codable{
       var userId: Int
       var id: Int
       var title: String
       var completed: Bool
}

JSON parsing với JSONDecoder

Sau khi tạo một network request. Chuyển đổi web application response dữ liệu thô sang Array Model.

Phần còn lại của JSON network request sẽ tương tự như process này. Chúng ta chỉ cần xử lý network response Data cho JSONDecoder. Không có thay đổi lớn cho protocol này.

do {
    //here dataResponse received from a network request
    let decoder = JSONDecoder() let model = try decoder.decode([User].self, from: dataResponse) //Decode JSON Response Data print(model) } catch let parsingError { print("Error", parsingError) }

 

Tại sạo tôi sử dụng model [User].self vì chúng ta nhận được response trong một Array format nếu response của bạn chỉ là Dictionary như:

 {
    "userId": 1,
    "id": 1,
    "title": "delectus aut autem",
    "completed": false
 }

Chúng ta cần sử dụng mode class như User.self cho Dictionary response.

do {
    //here dataResponse received from a network request
    let decoder = JSONDecoder() let model = try decoder.decode(User.self, from: dataResponse) //Decode JSON Response Data print(model.userId) //Output - 1221 } catch let parsingError { print("Error", parsingError) }

Custom key names

Chúng ta thay đổi codable của chúng ta với custom string keys nhưng nó phải trùng với JSON response keys của bạn. Nếu không thì bạn sẽ nhận error message.

1_a7CrBGrWlsEJnm1jj4BTzQ.png

Thêm custom keys cho Codable Model:

struct User: Codable{
       var userId: Int
       var id: Int
       var title: String
       var completed: Bool
       //Custom Keys 
       enum CodingKeys: String, CodingKey {
           case userId 
           case id = "serviceId"  //Custom keys
           case title = "titleKey" //Custom keys
           case completed
       }
}

Chúng ta làm nhiều hơn với Swifty . Tôi đã làm ở đây quá trình khởi tạo thông qua extension của model. CodingKeys enum sẽ xác nhận với CodingKey protocol

struct User: Codable {
       var userId: Int
       var id: Int
       var title: String
       var completed: Bool
}
extension User{
   enum CodingKeys: String, CodingKey {
           case userId
           case id
           case title
           case completed
   }
}

Phân tích cú pháp JSON phức tạp với Codable Protocol

{
  "branch": {
    "subject": 5,
    "total_students": 110,
    "total_books": 150
  },
  "Subject": [
    {
      "subject_id": 301,
      "name": "EMT",
      "pratical": false,
      "pratical_days": [
        "Monday",
        "Friday"
      ]
    },
    {
      "subject_id": 302,
      "name": "Network Analysis",
      "pratical": true,
      "pratical_days": [
        "Tuesday",
        "Thursday"
      ]
    }
  ]
}

Struct model cho JSON response. Tôi đã viết model như sau:

struct Students : Codable {
       struct Branch : Codable {
              let subject: Int
              let totalStudents: Int
              let totalBooks: Int
           private enum CodingKeys : String, CodingKey {
              case subject
              case totalStudents = "total_students"
              case totalBooks = "total_books"
           }
       }
     struct Subject : Codable {
             let subject_id: Int
             let name: String
             let pratical: Bool
             let pratical_days: [String]
      }
   let branch: Branch
   let subject: [Subject]
}

Tôi không phải làm gì phức táp trên model. Tôi đã có gắng sử dụng cách đơn giản nhất.

Parsing data từ JSON response

Tôi đã thể hiện ở đây sau khi làm network request tới web API. Chúng ta sử lý network response data thông qua Codable model của chúng ta. Không có khác biết gì lớn ở đây.

do {
   // data we are getting from network request
   let decoder = JSONDecoder()
   let response = try decoder.decode(Students.self, from: data)
   print(response.subject[0].name) //Output - EMT
} 

 

Cuối cùng chúng dã JSON parsing xong. Đây là quá trình đơn giản để xử ký bất kỳ network response data hoặc JSON object data trong code của bạn. Do vậy bạn có thể xử lý UI dựa trên JSON response data. Chúng ta cần map tất cả yêu cầu giá trị từ response theo yêu cầu.

Bình luận về bài viết này