#20 新手的 Swift JSON decode 練習題

rjjq
彼得潘的 Swift iOS / Flutter App 開發教室
7 min readAug 16, 2022

利用 apple marketing tools RSS generator 練習 JSON decode

這次的練習單純將條件限縮在查詢台灣地區的各類音樂類型 TOP50的歌單

網頁查詢結果

功能

  1. 可選擇不同的音樂類型 (Albums / Music Videos / Playlists / Songs)
  2. 選好類型將會自動於背景取得TOP 50的音樂資訊
  3. 按下按鍵將取得的音樂資訊,排入 Table View 中顯示 (有用到 Kingfisher 套件顯示音樂圖片)

步驟

  1. 拉一個主頁面及一個Table頁面

2. 依API回傳的資料,去設定 JSON decode 需要用到的資料格式(建立music.swift)

struct SearchResponse: Decodable {
let feed: Feed
}
struct Feed: Decodable {
let title: String
let results: [Item]
}
struct Item: Decodable {
let artistName: String?
let name: String
let releaseDate: String?
let artworkUrl100: URL?
let url: URL?
}

3. 設置 IBOutlet 及 參數

@IBOutlet weak var picker: UIPickerView!
var items = [Item]()
var pickerData = ["Albums", "Music Videos", "Playlists", "Songs"]
let musicTypes = ["albums", "music-videos", "playlists", "songs"]

4. 設置 IBAction 及 各函式

在 ViewController中 @IBSegueAction func show(_ coder: NSCoder) -> MusicTableViewController? {
guard items.count > 0, let controller = MusicTableViewController(coder: coder) else {return nil}

controller.items = items
return controller
}

func fetchItems(type: String) {
if let url = URL(string: "https://rss.applemarketingtools.com/api/v2/tw/music/most-played/50/\(type).json") {
URLSession.shared.dataTask(with: url) { data, response, error in
if let data {
do {
let decoder = JSONDecoder()
let searchResponse = try decoder.decode(SearchResponse.self, from: data)
DispatchQueue.main.async {
self.items = searchResponse.feed.results
}
} catch {
print(error)
}
}
}.resume()
}
}
extension ViewController: UIPickerViewDelegate, UIPickerViewDataSource {
func numberOfComponents(in pickerView: UIPickerView) -> Int {
return 1
}

func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
return pickerData.count
}

func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
return pickerData[row]
}

func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
print(musicTypes[row])
let type = musicTypes[row]

self.fetchItems(type: type)
}
}
在 MusicTableViewController中override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return items.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "\(MusicTableViewCell.self)", for: indexPath) as? MusicTableViewCell
let music = items[indexPath.row]
cell?.photoView.kf.setImage(with: music.artworkUrl100, placeholder: UIImage(systemName: "music.note"))
cell?.musicLabel.text = music.artistName
cell?.songLabel.text = music.name
cell?.rowLabel.text = "\(indexPath.row + 1)"

return cell!
}

成果

GitHub

參考

--

--