昨天我們學會了如何像「建築師」一樣規劃 MVC 架構,讓專案變得井然有序。今天,我們就要立刻學以致用,親手搭建一個結構清晰、功能酷炫的 App!
這次的主題,讓我們望向星空——我們將串接 NASA 的「每日天文一圖」API!你將學會如何使用滾筒式的 選取器(PickerView),讓使用者能輕鬆地選擇日期,並即時從 NASA 伺服器抓取回傳的太空美照。這將是我們第一個結合了 專業架構、UI 元件 與真實網路資料 的實戰專案!
Codable
將 JSON 結構對應到 Swift 的 struct
。Xib
中規劃 ImageView
, PickerView
, Button
的基本佈局。NetworkManager
,並處理各種潛在的網路錯誤。首先,前往 NASA Open APIs 申請 API Key。
填寫基本資料後,就會在信箱收到 API Key:
接著往下滑,選擇 APOD: Astronomy Picture of the Day:
點擊 Example query 範例連結,複製 JSON 回傳的內容:
打開 Json Parser Online,將 JSON 貼上:
對照右側結構,在 Xcode 中新增 apiNASA.swift
,建立資料結構:
struct apiNASA: Codable {
var date: String
var explanation: String
var hdurl: String
var media_type: String
var service_version: String
var title: String
var url: String
}
使用 Codable 可以自動解析 JSON,並方便與
NetworkManager
搭配。
今天我們先在 .xib
設計主要畫面,包含三個元件:
UIImageView
:顯示 NASA 天文圖片UIPickerView
:讓使用者選擇日期(年/月/日三欄)UIButton
:確認選擇日期後抓取圖片建議介面佈局:
------------------------
| UIImageView |
------------------------
| UIPickerView |
------------------------
| UIButton |
------------------------
記得拉好 Auto Layout 約束,避免元件在不同裝置跑版。
將網路請求集中管理,方便 MainViewController
直接呼叫:
import Foundation
class NetworkManager {
// 建立 singleton,方便整個專案使用
static let shared = NetworkManager()
// 私有建構子,避免外部再建立新的實例
private init() {}
// 封裝抓取 NASA APOD 資料的函式
func fetchNASAData(for date: String? = nil, completion: @escaping (Result<apiNASA, Error>) -> Void) {
// 1️⃣ API URL
// 記得將 "貼上你的API_KEY" 改成你申請的 Key
var urlString = "https://api.nasa.gov/planetary/apod?api_key=貼上你的API_KEY"
if let date = date {
// 如果有傳入日期,就加上 &date=yyyy-MM-dd
urlString += "&date=\(date)"
}
// 2️⃣ 將字串轉成 URL
guard let url = URL(string: urlString) else {
// 如果字串無法轉成 URL,直接回傳錯誤
completion(.failure(NSError(domain:"Invalid URL", code:0)))
return
}
// 3️⃣ 發送網路請求
URLSession.shared.dataTask(with: url) { data, response, error in
// 3a. 如果請求出現錯誤
if let error = error {
completion(.failure(error))
return
}
// 3b. 檢查 HTTP 狀態碼是否成功
if let httpResponse = response as? HTTPURLResponse, httpResponse.statusCode != 200 {
completion(.failure(NSError(domain: "HTTP Error", code: httpResponse.statusCode)))
return
}
// 3c. 確認有回傳資料
guard let data = data else {
completion(.failure(NSError(domain:"No data", code:0)))
return
}
// 4️⃣ 將 JSON 解析成 Swift 結構
do {
let decoder = JSONDecoder()
let result = try decoder.decode(apiNASA.self, from: data)
// 成功解析後,透過 completion 回傳資料
completion(.success(result))
} catch {
// 如果解析失敗,回傳錯誤
completion(.failure(error))
}
// 5️⃣ 啟動請求
}.resume()
}
}
static let shared = NetworkManager()
NetworkManager
實例,方便全域使用。@escaping (Result<apiNASA, Error>) -> Void
MainViewController
就能拿到資料更新畫面。apiNASA
結構)。Codable
讓解析非常簡單,不需要手動抓每個欄位。URLSession
的 completion handler
是在背景線程執行的。因此,明天當我們在 MainViewController
中拿到 NetworkManager
回傳的資料後,任何更新畫面的操作(如設定 UIImageView
的圖片)都必須被放到主線程 DispatchQueue.main.async
中執行,否則 App 可能會閃退或畫面無反應。今天,我們扮演了 NASA App 的「首席工程師」,完成了所有看不見但至關重要的幕後工程!
我們從一份來自 NASA 的藍圖(JSON)開始,學會了如何用 Codable
將它打造成堅固的資料模型。更厲害的是,你還親手建立了一個專業、可重複使用的網路引擎(NetworkManager
),它不僅採用了 Singleton
模式,還具備了完整的錯誤處理機制。
這個強大的網路層,是你從「單機 App」邁向「連網 App」的關鍵基石。「萬事俱備,只欠東風」——明天,我們就要把這陣東風(UI 互動)吹起來,讓一切完美運作!
明天,我們將回到 MainViewController
,扮演總指揮的角色。你將學會如何實作 UIPickerView
的 dataSource
與 delegate
,讓它能顯示年、月、日的滾動選項。
最精彩的部分是,當使用者按下按鈕後,我們將會呼叫 NetworkManager
去抓取 NASA 的資料,並學會在背景執行緒安全地更新 UI,將美麗的太空圖片顯示在畫面上。這將是將所有零件組合成一個完整產品的關鍵一課!
敬請期待《Day 25|Xcode 滾動選取:PickerView & NASA 實戰應用(第二天)》