日本娛樂新聞APP (網路下載資料)
串接第 3 方 API, 解析 JSON 資料, 轉換成自訂型別顯示
成品:最近事情不少這堂課補得斷斷續續,終於可以來寫網誌囉~
▲起先貪心構思很多,最後回歸基本功能練習但網誌仍寫很久= =
▲ 3 個物件 AutoLayout / StackView 還和我鬧不合?還好強者我朋友
▲還沒體會到用 do catch print error 美好的你請跟上時代腳步
▲無限輪迴聽上課影片到很厭世…
▲參考來源:彼得與同學(但他寫好複雜我幾乎沒有參考到 :P)
前置作業
▲ TableViewController + Navigation + ViewController (WebView)
▲新增 Swift File * 1 + Cocoa Touch Class * 3 ,取名後各自配好 + Cell ID
▲用客製 cell 才不會有滑動後才顯示圖片的不一致狀況產生
▲加 Label 與 ImageView 並用 AutoLayout / StackView
▲ Title Label 記得 Line 調 0 使其可變為多行
▲ cell 拉 segue 至 ViewController,並加 WebView 於 ViewController
依 JSON 對應自訂型別 (解碼 / 編碼),遵從 protocol Codable 的型別
▲彼得提供的第 3 方 API 連結整理,從中取得 JSON API,新聞請選這
▲自訂型別:SearchResponse
▲遵從 Codable ( 解碼:Decodable protocol + 編碼:Encodable protocol)
▲型別遵從,其屬性也要遵從如:String, Int, Date, URL, Array, Data 等
▲屬性名稱及其型別轉換不可打錯,想改名稱須用其他方法如:enum
▲ url 含特別字元,所以要用 String 特別處理才能轉成 URL
▲ JSON 物件不一定有的 key / 某 key 對應 value 可能為 null 時
➞要宣告為 optional
▲更詳細解說請參考彼得教學
NewsTableViewController.swift
▲ 生成 1 個 空白 Array,為顯示於表格上
var articles = [Article]()
▲cell 數量 = Array 數量
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return articles.count
}
NewsTableViewCell.swift:拉 Outlet
@IBOutlet weak var titleLabel: UILabel!
@IBOutlet weak var dateLabel: UILabel!@IBOutlet weak var photoImageView: UIImageView!
回 NewsTableViewController.swift
▲防止重覆利用的 cell 顯示之前照片
➞未抓完 / 沒圖片時會顯示 SF Symbols 的 photo 圖
▲利用 URLSession 在背景抓 Data 不會卡住 UI
▲如有抓到資料便在 main thread 執行 UI 相關程式
➞將抓到的 Data 轉成 UIImage
▲呼叫 resume() 才會開始執行任務 (啟動後才會開始抓資料)
☆其實抓圖可用套件 Kingfisher 簡化為 1 行不用 URLSession (彼得教學)
➞ import Kingfisher
➞ cell.photoImageView.kf.setImage(with: url)
❇️ 寫抓資料的 function:超長…要往下拉才看得到程式碼圖
▲將 API 網址轉成 URL,網址含非英文數字等特定符號時有 2 種方法解
➞ addingPercentEncoding,在網址後加以下程式 ↓
.addingPercentEncodinf(withAllowedCharacters: .urlQueryAllowed)
➞用 baseURL, URLComponents, URLQueryItem 產生 URL (彼得教學)
▲要寫網路功能都和 URLSession
有關 (連線 / 送出 request 的意思)
➞用 shared 產生 1 共用的 session 並以此呼叫 dataTask func 抓 / 上傳資料
➞抓完資料無論成功與否,會給 3 參數讓我們在 closure 內去執行
➞加 resume()
才會開始抓資料及執行任務
▲判斷有無抓到資料後可先印出 JSON 確認,utf8 為各語言符號(此省)
let content = String(data: data, encoding: .utf8) { print(content)}
➞用 JSONDecoder()
解碼 JSON 抓下來的資料
➞ JSONDecoder 解析時間的 dateDecodingStrategy
(彼得教學)
➞呼叫 decode func 解碼,此 func 會有 throws 要用 try?,簡短但無法印錯let searchResponse = try? decoder.decode(SearchResponse.self, from: data)
▲可改用 do catch
配合 try
寫法便能印出錯誤,錯誤解析參考彼得教學
➞ do 裡做想嘗試 (try 無問號) 之事,失敗時產生錯誤並執行 catch
➞用 JSONDecoder 將型別 Data 的 JSON 資料變成型別 SearchResponse
decode func 的參數 Type 傳入想生成東西之型別,傳入型別的寫法:型別名字 + .self
➞存入原為空白的 Array,之前 struct 有設 optional 所以要加!
➞ reloadData
觸發 TableView DataSource 相關 function 後畫面才會更新
ViewDidLoad:不用每次下全部圖,因此抓圖寫在 cell 裡 不在此 func 裡
override func viewDidLoad() {
super.viewDidLoad() fetchArticles()
}
完整程式碼
SearchResponse.swif,NewsTableViewController
NewsTableViewCell,WebViewController