#15 利用 Airtable 開發 iOS App

這次作業我打算藉著先前地圖猜謎app延伸來完成。

這個app將從 Airtable 獲取數據,並在 UITableView 中顯示地圖名稱和圖片。其中使用 URLSession 進行網絡請求,還涵蓋了使用第三方庫Kingfisher 讀取網路圖片。

步驟 1:設置 Airtable 資料庫

首先,在 Airtable 中創建了一個資料庫(base),並添加了所需的表格和字段。在這個例子中,我們有一個名為 mapInfo 的表格,包含以下字段:

  • areaName:區域名稱
  • areaInfo:區域資訊(例如介紹連結)
  • areaImage:區域圖像(附件類型)

步驟 2:定義資料結構

定義與 Airtable 資料結構對應的 Swift 結構。創建一個名為 Struct.swift 的文件:

import Foundation

struct MapInfo: Codable {
let records: [Record]
}

struct Record: Codable {
let id, createdTime: String
let fields: Fields
}

struct Fields: Codable {
let areaImage: [AreaImage]
let areaInfo: String
let areaName: String
}

struct AreaImage: Codable {
let id: String
let width, height: Int
let url: String
let filename: String

步驟 3:實現 Airtable API 串接

我們需要從 Airtable 獲取數據,並將其解碼為 MapInfo 結構。創建一個名為 NetworkManager.swift 的文件:

import Foundation

let apiKey = APIKey.default
var mapInfoData: MapInfo?
func fetchData(completion: @escaping (MapInfo?) -> Void) {
if let url = URL(string: "https://api.airtable.com/v0/app1MfmI8sP5PmaSp/mapInfo") {
var request = URLRequest(url: url)
// 設置授權標頭
request.setValue("Bearer \(apiKey)", forHTTPHeaderField: "Authorization")

// 發送 HTTP 請求
URLSession.shared.dataTask(with: request) { data, response, error in
if let data {
// 列印 JSON 資料
let decoder = JSONDecoder()
do {
// 將 JSON 資料解碼成 MapInfo 結構
let result = try decoder.decode(MapInfo.self, from: data)
mapInfoData = result // 將解碼結果存入全域變數
completion(result) // 調用完成閉包
} catch {
print(error)
completion(nil) // 如果解碼失敗,傳回 nil
}
} else if let error {
print(error)
completion(nil) // 如果請求失敗,傳回 nil
}
}.resume()
}
}

步驟 4:設置 TableView

接下來,我們需要設置 UITableView 來顯示從 Airtable 獲取的數據。創建一個名為 MapInfoTableViewController.swift 的文件:

import UIKit
import Kingfisher

class MapInfoTableViewController: UITableViewController {
var mapInfoData: MapInfo?

override func viewDidLoad() {
super.viewDidLoad()
fetchData { data in
DispatchQueue.main.async {
if let data = data {
// 使用 data 做其他處理
self.mapInfoData = data
self.tableView.reloadData() // 重新加載表格視圖
} else {
// 處理數據加載失敗的情況
let alert = UIAlertController(title: "Error", message: "Failed to load data", preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
self.present(alert, animated: true, completion: nil)
}
}
}
}

// MARK: - Table view data source

override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}

override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return mapInfoData?.records.count ?? 0
}

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "MapInfoTableViewCell", for: indexPath) as! MapInfoTableViewCell

if let record = mapInfoData?.records[indexPath.row] {
cell.mapName.text = record.fields.areaName
cell.url = record.fields.areaInfo

if let url = record.fields.areaImage.first?.url {
cell.mapImage.kf.setImage(with: URL(string: url))
}
}
return cell
}
}

步驟 5:設置 TableView Cell

創建一個名為 MapInfoTableViewCell.swift 的文件:

import UIKit
import SafariServices

class MapInfoTableViewCell: UITableViewCell, SFSafariViewControllerDelegate {

@IBOutlet weak var mapName: UILabel!
@IBOutlet weak var mapImage: UIImageView!
var url: String?

override func awakeFromNib() {
super.awakeFromNib()
}

override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
}

func openUrl() {
guard let urlString = url, let url = URL(string: urlString) else { return }
let safariVC = SFSafariViewController(url: url)
safariVC.delegate = self
UIViewController().present(safariVC, animated: true, completion: nil)
}
}

結語

通過這次作業,我學習到串接 Airtable api 獲取地圖資訊並在 TableView 中顯示,並利用 Kingfisher 庫讀取網路圖片。此外,我還設置了 TableView 的 Delegate 和 DataSource,實現了數據的顯示和管理,接下來我想嘗試把api中的連結做成按鈕,並顯示在safari上。

--

--