Swift 4 JSON

在 Swift 之中,JSON (JavaScript Object Notation) 的型別為 [String: Any], 也就是一個 Dictionary 的概念,以一組 Key 對應一組 Value。 大多數會碰到 JSON 格式是在做網路溝通時, 使用 JSON 格式並 encode 成 Data 的型態在傳輸資料。

Swift 3 以前

我們從 URLSession.shared.dataTask 的 handler 之中, 會得到 data、response 及 error,其中的 data 會使用下面的方式才轉換成 JSON:

/* Create a Foundation object from JSON data. Set the NSJSONReadingAllowFragments option if the parser should allow top-level objects that are not an NSArray or NSDictionary. Setting the NSJSONReadingMutableContainers option will make the parser generate mutable NSArrays and NSDictionaries. Setting the NSJSONReadingMutableLeaves option will make the parser generate mutable NSString objects. If an error occurs during the parse, then the error parameter will be set and the result will be nil.
       The data must be in one of the 5 supported encodings listed in the JSON specification: UTF-8, UTF-16LE, UTF-16BE, UTF-32LE, UTF-32BE. The data may or may not have a BOM. The most efficient encoding to use for parsing is UTF-8, so if you have a choice in encoding the data passed to this method, use UTF-8.
     */
open class func jsonObject(with data: Data, options opt: JSONSerialization.ReadingOptions = []) throws -> Any

接著我們再來對 JSON 的 Key 和 Value 來進行拆解:

/*
{
    "status": true,
    "user": {
        "ID": "1234567890",
        "name": "Archie",
        "email": "example@example.com"
}
*/

guard let status = result["status"] as? Bool,
    let ID = (result["user"] as? [String: Any])?["ID"] as? String,
    let name = (result["user"] as? [String: Any])?["name"] as? String,
    let email = (result["user"] as? [String: Any])?["email"] as? String else {
        throw Error
}

而巢狀式的 JSON 格式,寫起來的 code 就會越長,進而衍生出 SwiftyJSON,有興趣的可以自行看一下。

Swift 4

那 Swift 4 做了哪種改變呢? 在 Foundation 裡頭,增加了 Encoder/Decoder 相關的內容, 而這邊先以 JSON 作為主要的內容。 以 User 作為例子:

/*
{
    "name": "Archie",
    "email": "example@example.com",
    "status: "Active",
    "updated_time": "2017-09-20T00:00:00Z"
}
*/

enum UserStatus: String, Codable {
    case active = "Active"
    case disable = "Disable:"
}

struct User: Codable {
    var name: String
    var email: String
    var status: UserStatus
    var updatedTime: Date
    
    // if keys need to replace by others
    enum CodingKeys : String, CodingKey {
          case name
          case email 
          case status 
          case updatedTime = "updated_time"
    }
}

// encoder
let encoder = JSONEncoder()

// set date encoding strategy to iso8601
// default is TimeInterval
encoder.dateEncodingStrategy = .iso8601

// user convert to data
let data = try! encoder.encode(user)

// decoder
let decoder = JSONDecoder()

// data convert to user
let user = try! decoder.decode(User.self, from: data)

其中,Codable 是指 Encodable 和 Decodable, 若你只需要做 data parse 的話,也可以僅宣告 Decodable。

comments powered by Disqus