今天教大家內部的功能怎麼設計!
首先我們要先處理好 Url 的編碼
接著需要讓我們的 LifeCycle 包進去能夠呼叫我們設定的 API
所以要設計一個 function 去填入
重點是我們會將 Url 分為兩個不同區塊去設計
// 處理URL編碼
func LegitimateURL(requestURL: String) -> URL? {
guard let legitimateURL = requestURL.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed),
let url = URL(string: legitimateURL) else {
print("無法創建有效的 URL")
return nil
}
return url
}
// 呼叫天氣API
func callAPI() {
guard let selectedArea = selectedArea else {
print("沒有選擇的地區")
return
}
let baseURL = "https://opendata.cwa.gov.tw/api/v1/rest/datastore/F-C0032-001?Authorization = 這裡要填入你的授權碼"
let cityParam = "&locationName=\(selectedArea)"
let fullURLString = baseURL + cityParam
guard let requestURL = LegitimateURL(requestURL: fullURLString) else {
print("無法創建請求 URL")
return
}
// 顯示載入指示器
let activityIndicator = UIActivityIndicatorView(style: .medium)
activityIndicator.center = view.center
activityIndicator.hidesWhenStopped = true
view.addSubview(activityIndicator)
activityIndicator.startAnimating()
// 執行API請求
URLSession.shared.dataTask(with: requestURL) { [weak self] (data, response, error) in
// 停止載入指示器
DispatchQueue.main.async {
activityIndicator.stopAnimating()
activityIndicator.removeFromSuperview()
}
// 錯誤處理
if let error = error {
print("請求失敗: \(error.localizedDescription)")
self?.showAlert(title: "請求失敗", message: "無法獲取天氣數據")
return
}
// 檢查HTTP狀態碼
if let httpResponse = response as? HTTPURLResponse {
if !(200...299).contains(httpResponse.statusCode) {
print("伺服器回應錯誤: \(httpResponse.statusCode)")
self?.showAlert(title: "伺服器錯誤", message: "HTTP狀態碼: \(httpResponse.statusCode)")
return
}
}
guard let data = data else {
print("沒有接收到數據")
self?.showAlert(title: "數據錯誤", message: "沒有接收到任何數據")
return
}
// 解析JSON資料
let decoder = JSONDecoder()
do {
let weatherData = try decoder.decode(weatherData.self, from: data)
// 更新UI
DispatchQueue.main.async {
self?.weatherData2 = weatherData
self?.TView.reloadData()
}
} catch {
print("JSON 解析失敗: \(error.localizedDescription)")
self?.showAlert(title: "數據解析錯誤", message: "無法解析天氣數據")
}
}.resume()
}
extension 部分就沒什麼要注意的了
相信我們已經教了好幾次的 tableView 設定大家都有肌肉記憶了吧!
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return weatherData2?.records.location.first?.weatherElement.first?.time.count ?? 0
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell = tableView.dequeueReusableCell(withIdentifier: "AreaTableViewCell", for: indexPath) as? AreaTableViewCell else {
return UITableViewCell()
}
// 取得天氣資料
let minT = weatherData2?.records.location[0].weatherElement[2].time[indexPath.row].parameter.parameterName ?? " "
let maxT = weatherData2?.records.location[0].weatherElement[4].time[indexPath.row].parameter.parameterName ?? " "
// 獲取並格式化時間
let startTimeString = weatherData2?.records.location[0].weatherElement[0].time[indexPath.row].startTime ?? " "
let formattedTime = formatTime(startTimeString)
// 設定單元格內容
cell.lbTime.text = formattedTime // 使用格式化後的時間
cell.lbWx.text = weatherData2?.records.location[0].weatherElement[0].time[indexPath.row].parameter.parameterName ?? " "
cell.lbMinT.text = "\(maxT)°C " // 最高溫度
cell.lbCl.text = weatherData2?.records.location[0].weatherElement[3].time[indexPath.row].parameter.parameterName ?? " " // 舒適度
cell.lbMaxT.text = "\(minT)°C" // 最低溫度
// 設定天氣圖示
if let weatherCode = weatherData2?.records.location[0].weatherElement[0].time[indexPath.row].parameter.parameterValue {
setWeatherIcon(cell: cell, weatherCode: weatherCode)
}
return cell
}
// 設定天氣圖示
private func setWeatherIcon(cell: AreaTableViewCell, weatherCode: String) {
if let code = Int(weatherCode) {
let imageName: String
switch code {
case 1:
imageName = "sun.max" // 晴天
case 2, 3:
imageName = "cloud.sun" // 多雲
case 4, 5, 6, 7:
imageName = "cloud" // 陰天
case 8, 9, 10, 11, 12, 13, 14:
imageName = "cloud.rain" // 雨天
case 15, 16, 17, 18:
imageName = "cloud.bolt.rain" // 雷雨
case 19, 20, 21, 22:
imageName = "snowflake" // 雪
default:
imageName = "cloud"
}
if #available(iOS 13.0, *) {
cell.imgCloud.image = UIImage(systemName: imageName)
}
}
}