使用 Apple Foundation 和 Swift 標準庫進行 JSON 序列化編碼和解碼
該 JSONSerialization 類是內建到蘋果的基礎框架。
Version = 2.2
閱讀 JSON
JSONObjectWithData
函式接受 NSData
,並返回 AnyObject
。你可以使用 as?
將結果轉換為你期望的型別。
do {
guard let jsonData = "[\"Hello\", \"JSON\"]".dataUsingEncoding(NSUTF8StringEncoding) else {
fatalError("couldn't encode string as UTF-8")
}
// Convert JSON from NSData to AnyObject
let jsonObject = try NSJSONSerialization.JSONObjectWithData(jsonData, options: [])
// Try to convert AnyObject to array of strings
if let stringArray = jsonObject as? [String] {
print("Got array of strings: \(stringArray.joinWithSeparator(", "))")
}
} catch {
print("error reading JSON: \(error)")
}
當頂級物件不是陣列或字典時,你可以傳遞 options: .AllowFragments
而不是 options: []
以允許讀取 JSON。
寫 JSON
呼叫 dataWithJSONObject
將與 JSON 相容的物件(帶有字串,數字和 NSNull
的巢狀陣列或字典)轉換為以 UTF-8 編碼的原始 NSData
。
do {
// Convert object to JSON as NSData
let jsonData = try NSJSONSerialization.dataWithJSONObject(jsonObject, options: [])
print("JSON data: \(jsonData)")
// Convert NSData to String
let jsonString = String(data: jsonData, encoding: NSUTF8StringEncoding)!
print("JSON string: \(jsonString)")
} catch {
print("error writing JSON: \(error)")
}
你可以通過 options: .PrettyPrinted
而不是 options: []
進行漂亮列印。
Version = 3.0
Swift 3 中的行為相同但語法不同。
do {
guard let jsonData = "[\"Hello\", \"JSON\"]".data(using: String.Encoding.utf8) else {
fatalError("couldn't encode string as UTF-8")
}
// Convert JSON from NSData to AnyObject
let jsonObject = try JSONSerialization.jsonObject(with: jsonData, options: [])
// Try to convert AnyObject to array of strings
if let stringArray = jsonObject as? [String] {
print("Got array of strings: \(stringArray.joined(separator: ", "))")
}
} catch {
print("error reading JSON: \(error)")
}
do {
// Convert object to JSON as NSData
let jsonData = try JSONSerialization.data(withJSONObject: jsonObject, options: [])
print("JSON data: \(jsonData)")
// Convert NSData to String
let jsonString = String(data: jsonData, encoding: .utf8)!
print("JSON string: \(jsonString)")
} catch {
print("error writing JSON: \(error)")
}
注意:以下內容目前僅適用於 Swift 4.0 及更高版本。
從 Swift 4.0 開始,Swift 標準庫包含 Encodable
和 Decodable
協議,以定義資料編碼和解碼的標準化方法。採用這些協議將允許 Encoder
和 Decoder
協議的實現獲取你的資料,並將其編碼或解碼到外部表示(如 JSON)和從外部表示解碼。符合 Codable
協議結合了 Encodable
和 Decodable
協議。現在,這是在程式中處理 JSON 的推薦方法。
自動編碼和解碼
使型別可編碼的最簡單方法是將其屬性宣告為已經知道的型別。這些型別包括標準庫型別,如 String
,Int
和 Double
; 和基礎型別,如 Date
,Data
和 URL
。如果型別的屬性是可編碼的,則型別本身將通過簡單地宣告一致性自動符合 Codable
。
考慮以下示例,其中 Book
結構符合 Codable
。
struct Book: Codable {
let title: String
let authors: [String]
let publicationDate: Date
}
請注意,如果
Array
和Dictionary
等標準集合包含可編碼型別,則它們符合Codable
。
通過採用 Codable
,Book
結構現在可以使用 Apple Foundation 類 JSONEncoder
和 JSONDecoder
編碼到 JSON 並從 JSON 解碼,即使 Book
本身不包含專門處理 JSON 的程式碼。也可以通過分別符合 Encoder
和 Decoder
協議來編寫自定義編碼器和解碼器。
編碼為 JSON 資料
// Create an instance of Book called book
let encoder = JSONEncoder()
let data = try! encoder.encode(book) // Do not use try! in production code
print(data)
設定
encoder.outputFormatting = .prettyPrinted
以便於閱讀。 ##從 JSON 資料解碼
從 JSON 資料解碼
// Retrieve JSON string from some source
let jsonData = jsonString.data(encoding: .utf8)!
let decoder = JSONDecoder()
let book = try! decoder.decode(Book.self, for: jsonData) // Do not use try! in production code
print(book)
在上面的例子中,
Book.self
通知解碼器應該解碼 JSON 的型別。
獨佔編碼或解碼
有時你可能不需要資料既可編碼又可解碼,例如當你只需要從 API 讀取 JSON 資料時,或者你的程式僅將 JSON 資料提交給 API 時。
如果你只想編寫 JSON 資料,請將你的型別與 Encodable
保持一致。
struct Book: Encodable {
let title: String
let authors: [String]
let publicationDate: Date
}
如果你只想閱讀 JSON 資料,請將你的型別符合 Decodable
。
struct Book: Decodable {
let title: String
let authors: [String]
let publicationDate: Date
}
使用自定義鍵名稱
API 經常使用除 Swift 標準駝峰案例之外的命名約定,例如蛇案例。在解碼 JSON 時,這可能會成為一個問題,因為預設情況下,JSON 鍵必須與你的型別的屬性名稱完全對齊。要處理這些情況,你可以使用 CodingKey
協議為你的型別建立自定義鍵。
struct Book: Codable {
// ...
enum CodingKeys: String, CodingKey {
case title
case authors
case publicationDate = "publication_date"
}
}
CodingKeys
是針對採用 Codable
協議的型別自動生成的,但是通過在上面的示例中建立我們自己的實現,我們允許我們的解碼器將本地駝峰情況 publicationDate
與由蛇提供的蛇盒 publication_date
相匹配。