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)
, Array
, String
, Bool
, Number.
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.
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
- Dán App Transport Security vào plist file trong projet của bạn
<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.
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.