在昨天的教學中,我們建立了主畫面 MainViewController
,讓使用者能夠選擇一個縣市,並按下按鈕後跳轉到下一個畫面。
今天,我們要進入這個「第二頁」——SecondViewController
,負責顯示該縣市的天氣資料,並學會如何在 Swift 裡呼叫 API、解析 JSON,再顯示在畫面上。
這個畫面要做到:
整體流程如下:
MainViewController ➝ 傳遞城市 ➝ SecondViewController ➝ 呼叫 API ➝ 顯示結果
//
// SecondViewController.swift
// Weather API
//
// Created by imac-2156 on 2025/7/30.
//
import UIKit // 匯入 UIKit,用於 UI 控制與操作
// 第二個畫面控制器,用來顯示特定縣市的天氣資料
// 同時遵守 UITableViewDelegate 與 UITableViewDataSource 協議
class SecondViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
// MARK: - IBOutlet
@IBOutlet weak var btnData2: UIButton! // 返回按鈕
@IBOutlet weak var tbvWeather: UITableView! // 顯示天氣資料的 TableView
@IBOutlet weak var lbCt: UILabel! // 顯示所選城市名稱的 Label
// MARK: - Property
var selectedArea: String? // 從上一頁傳過來的縣市名稱
var WeatherData2: WeatherData? // 用來儲存 API 回傳的天氣資料
// MARK: - LifeCycle
override func viewDidLoad() {
super.viewDidLoad()
// 設定 TableView 的 delegate 與 dataSource
tbvWeather.delegate = self
tbvWeather.dataSource = self
// 註冊自訂 Cell,使用 XIB 檔案
tbvWeather.register(UINib(nibName: "SecondTableViewCell", bundle: nil),
forCellReuseIdentifier: "SecondTableViewCell")
// 顯示所選縣市名稱
lbCt.text = selectedArea
// 呼叫 API 取得天氣資料
callAPI()
}
// MARK: - IBAction
@IBAction func btnData2Tapped(_ sender: UIButton) {
// 點擊返回按鈕,關閉當前畫面
self.dismiss(animated: true, completion: nil)
}
// MARK: - Function
/// 將傳入的字串轉為合法 URL
func legitimateURL(requestURL: String) throws -> URL {
guard let urlString = requestURL.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed),
let url = URL(string: urlString) else {
throw URLError(.badURL)
}
return url
}
/// 呼叫中央氣象局 API 取得天氣資料
func callAPI() {
// 確認使用者有選擇縣市
guard let city = selectedArea else {
print("No area selected")
return
}
// 使用 URLComponents 來組合 URL
var components = URLComponents(string: "https://opendata.cwa.gov.tw/api/v1/rest/datastore/F-C0032-001")!
components.queryItems = [
URLQueryItem(name: "Authorization", value: "CWA-409C266F-4F25-4DE2-8CBE-530E562DCD45"),
URLQueryItem(name: "locationName", value: city)
]
print("selectedCity = " + city)
guard let requestURL = components.url else {
print("URL 生成失敗")
return
}
// 建立 URLSession 請求 API
URLSession.shared.dataTask(with: requestURL) { [weak self] (data, response, error) in
// 錯誤處理
if let error = error {
print(error.localizedDescription)
}
// 印出 HTTP 回應狀態
if let response = response as? HTTPURLResponse {
print("====================")
print(response)
print("====================")
}
// 解析 JSON
if let data = data {
let decoder = JSONDecoder()
do {
self?.WeatherData2 = try decoder.decode(WeatherData.self, from: data)
print("====================")
print(self?.WeatherData2 ?? "")
print("====================")
// 回主執行緒更新 UI
DispatchQueue.main.async {
self?.tbvWeather.reloadData()
}
} catch {
print("JSON 解析錯誤:\(error.localizedDescription)")
if let jsonString = String(data: data, encoding: .utf8) {
print("原始 JSON 資料:\(jsonString)")
}
}
}
}.resume()
}
}
// MARK: - TableView DataSource & Delegate
extension SecondViewController {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
print(WeatherData2?.records.location[0].weatherElement[0].time.count ?? 3)
return WeatherData2?.records.location[0].weatherElement[0].time.count ?? 3
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "SecondTableViewCell", for: indexPath) as! SecondTableViewCell
if let weatherData = WeatherData2 {
cell.configure(with: weatherData, index: indexPath.row)
}
return cell
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 200
}
}
URLSession.shared.dataTask
是 iOS 中最常用的網路請求方式。
這裡我們利用 URLComponents
組合查詢參數,避免手動字串拼接出錯。
完成後會取得一份 JSON,再由前面建立的 WeatherData
結構解析。
這裡的關鍵在:
self?.WeatherData2 = try decoder.decode(WeatherData.self, from: data)
透過 Codable
,整份 JSON 會自動轉換成我們的 Swift 結構,不需手動取 key。
API 回傳的天氣資料中,每個縣市會包含多個時間區間。
因此我們利用:
weatherElement[0].time.count
作為列數來源,每個 cell 會透過 SecondTableViewCell
顯示一段時間的預報。
第二頁的畫面元件如下:
搭配 XIB 自訂 cell,就能靈活控制每筆資料的呈現。
今天的內容讓我們成功打通了天氣資料的完整流程:
從主畫面選擇城市 ➝ 呼叫氣象局 API ➝ 顯示天氣結果。
透過 URLSession
與 Codable
,我們能快速完成資料請求與轉換。
接下來,下一篇將會介紹 自訂的 TableViewCell(SecondTableViewCell),讓畫面能夠更漂亮地顯示每筆天氣資訊。