#36 使用 JSONDecoder 把 JSON 轉換成自訂型別的資料

練習目的:練習 JSON decode(iTunes、Dcard)

利用 JSON Editor Online 排版JSON 資料,可以更清楚看出分層:

iTunes 搜尋 swift 當例子,API 的網址為:

https://itunes.apple.com/search?term=swift&media=music

先分層JSON,JSON 對應的自訂型別,當 JSON 愈多層,愈多 { } 時,需要定義愈多的 struct

第一層資料:

有兩個key,分別是resultCount、result

struct 自訂第一層資料格式,命名為 SearchResponse,兩個參數型別格式、命名必須跟JSON回傳的一模一樣,results有50筆資料,用array儲存,命名為[StoreItem]

第二層資料:

results中的資料,沒有再包{},可知此JSON就兩層

struct 自訂第二層資料格式,命名為StoreItem,定義要抓的資料的key、型別格式,有些資料會是optional,有可能為nil,需加上?

解析 JSON 資料的方法(利用 JSONDecoder)

執行結果

searchResponse.results[2].trackName
searchResponse.results[3].trackName

程式說明:

  1. 不會卡住 UI 的下載方法,利用 URLSession,dataTask回傳抓資料的任務

dataTask(with:completionHandler:) 的 completionHandler

completionHandler: (Data?,URLResponse?, Error?) -> Void) ->
URLSessionDataTask

• data: 抓到的資料
• response: 後台回傳抓資料的相關結果
•error: 錯誤資訊

let urlString = "https://itunes.apple.com/search?term=swift&media=music&country=tw"if let url = URL(string: urlString){URLSession.shared.dataTask(with: url) { data, response, error in...
...
...
}

2. JSONDecoder解碼的物件,把JSON的資料轉換成自訂型別

let decoder = JSONDecoder()

3. JSONDecoder 解析時間的 DateDecodingStrategy

decoder.dateDecodingStrategy = .iso8601

4. do catch:有可能會丟錯誤出來的程式可以用do catch寫

do{}:寫要試的內容

catch{}:有錯誤要跑到catch

do{let searchResponse = try decoder.decode(SerchResponse.self, from: data)
//呼叫decoder的function decode()
//要將資料變成什麼型別,由第一個參數決定,所以傳入要轉的型SerchResponse.self,型別本身要是資料需要加.self
print(searchResponse.results[2].trackName)}catch{print(error)}

5. resume啟動

.resume()

完整程式碼:

Dcard當例子,API 的網址為:

https://dcard.tw/_api/posts

目前無法直接連到 API 抓資料,若想測試可從 Safari 連到 API 網址,抓取 JSON 後將 JSON 貼到程式裡

多行字串JSON 解析,利用三個雙引號的多行字串包含 JSON 資料,然後呼叫 function data(using:) 得到 Data 型別的 JSON 資料,此時得到的資料就像我們利用 URLSessionTask 從網路下載的資料

****JSON字串變data,而不是從url****

let data = """...
...
...
"""..data(using: .utf8)!

第一層資料:

命名為PostResponse,定義要抓的資料的key、型別格式

第二層資料:

MediaMeta為array,命名為Media

解析 JSON 資料的方法(利用 JSONDecoder)

#由於JSON第一層為Array,所以在 decode 時傳入的型別加上 [ ] ,例如上方的[PostResponse]

執行結果

postResponse[8].title
postResponse[10].title

--

--