12/08/2018, 15:34

Ultimate Guide to JSON Parsing With Swift 4

Mở đầu Trong bài viết trước, tôi đã giới thiệu một số func mới trong Swift 4. Ở bài viết này, tôi sẽ giới thiệu cơ bản về Parsing JSON data trong Swift 4 mà Apple đã cung cấp sẵn cho chúng ta. The Basics Ví dụ ta có một cấu trúc JSON trả về như sau: { "name": "Endeavor", "abv": ...

Mở đầu

Trong bài viết trước, tôi đã giới thiệu một số func mới trong Swift 4. Ở bài viết này, tôi sẽ giới thiệu cơ bản về Parsing JSON data trong Swift 4 mà Apple đã cung cấp sẵn cho chúng ta.

The Basics

Ví dụ ta có một cấu trúc JSON trả về như sau:

{
    "name": "Endeavor",
    "abv": 8.9,
    "brewery": "Saint Arnold",
    "style": "ipa"
}

Và chúng ta có một struct Swift Beer có các thuộc tính sau:

enum BeerStyle : String {
    case ipa
    case stout
    case kolsch
    // ...
}

struct Beer {
    let name: String
    let brewery: String
    let style: BeerStyle
}

Trong swift 4, để convert từ file JSON như trên ra một Beer instance, ta sử dụng Codable. Codable là một kiểu mới trên swift 4 kết hợp bao gồm Encodable & Decodable.

enum BeerStyle : String, Codable {
   // ...
}

struct Beer : Codable {
   // ...
}

Tiếp theo chúng ta chỉ cẩn tạo một decoder

let jsonData = jsonString.data(encoding: .utf8)!
let decoder = JSONDecoder()
let beer = try! decoder.decode(Beer.self, for: jsonData)

Nếu muốn encode lại về định dạng JSON, ta thực hiện như sau:

let encoder = JSONEncoder()
let data = try! encoder.encode(beer)

Nếu API trả về một mảng các instance:

[
  {
    "beer" : {
      "id": "uuid12459078214",
      "name": "Endeavor",
      "abv": 8.9,
      "brewery": "Saint Arnold",
      "style": "ipa"
    }
  }
]

thì ta parsing response như sau:

let decoder = JSONDecoder()
let beers = try decoder.decode([Beer].self, from: data)

Handling Dates

JSON không có kiểu dữ liệu Date, vì vậy chúng được liệt kê trong một số biểu diễn một số định dạng khác nhau. Thông thường điều này được thực hiện với định dạng ngày tháng theo tiêu chuẩn ISO 8601 và sau đó được serialized như một chuỗi. Hoặc các định dạng khác có thể là số giây (hoặc mili giây) kể từ ngày tham chiếu (thông thường là 1970).

Trước đây, chúng ta phải tự giải quyết vấn đề này, cung cấp một trường string trên kiểu dữ liệu của chúng ta và sau đó sử dụng trường DateFormatter của chúng ta để sắp xếp ngày tháng từ các giá trị chuỗi và ngược lại.

Với JSONEncoder và JSONDecoder, điều này đã được thực hiện cho chúng ta. Mặc định, chúng sẽ sử dụng .deferToDate làm kiểu xử lý Date:

struct Foo : Encodable {
    let date: Date
}

let foo = Foo(date: Date())
try! encoder.encode(foo)
{
  "date" : 519751611.12542897
}

Và cũng có thể chuyển về định dạng .iso8601 :

encoder.dateEncodingStrategy = .iso8601
{
  "date" : "2017-06-21T15:29:32Z"
}

Handling Floats

Floats và là định dạng khác mà JSON không hoàn toàn khớp với Swift's Float. Điều gì xảy ra nếu máy chủ trả về một "NaN" không hợp lệ như một chuỗi? Điều gì về positive hoặc negative Infinity? Nó không thể map với bất kỳ giá trị cụ thể nào trong Swift. The default implementation is .throw, meaning if the decoder encounters these values then an error will be raised, but we can provide a mapping if we need to handle this:

Thông thường chúng ta thực hiện việc bắt exeption, còn bây giờ chúng ta có thể xử lý nó như sau:

{
   "a": "NaN",
   "b": "+Infinity",
   "c": "-Infinity"
}
struct Numbers : Decodable {
  let a: Float
  let b: Float
  let c: Float
}
decoder.nonConformingFloatDecodingStrategy =
  .convertFromString(
      positiveInfinity: "+Infinity",
      negativeInfinity: "-Infinity",
      nan: "NaN")

let numbers = try! decoder.decode(Numbers.self, from: jsonData)
dump(numbers)

Trả về cho ta:

▿ __lldb_expr_71.Numbers
  - a: inf
  - b: -inf
  - c: nan

Bạn có thể làm ngược lại với nonConformingFloatEncodingStrategy của JSONEncoder.

Đây không phải là điều bạn cần trong trường hợp đa số, nhưng một ngày nào đó nó có ích.

Handling Data

Đôi khi bạn sẽ tìm thấy các API gửi các bit dữ liệu nhỏ dưới dạng chuỗi được mã hoá base64. Để xử lý việc này, bạn có thể sử dung JSONEncoder : .base64 .custom( (Data, Encoder) throws -> Void) Để decode, bạn có thể sử dụng JSONDecoder: .base64 .custom ((Decoder) throws -> Data)

Tổng kết

Ở trên, tôi đã giới thiệu cơ bản về cách Parsing Data JSON trên swift 4, phương pháp xử lý một số kiểu dữ liệu thông dụng sử dụng công cụ có sẵn mà Apple cung cấp. Trong phần tiếp theo tôi sẽ tiếp tục giới thiệu tới các bạn các thuộc tính nâng cao của Codable để Decode và encode JSON format.

Nguồn:

https://developer.apple.com/documentation/swift/codable http://benscheirman.com/2017/06/ultimate-guide-to-json-parsing-with-swift-4/

0