今回は、以前作成した地図クイズアプリを基に発展させて行います。このアプリはAirtableからデータを取得し、UITableViewに地図の名称と画像を表示します。ネットワークリクエストにはURLSessionを使用し、サードパーティライブラリのKingfisherを使ってネットワーク画像を読み込みます。
Airtableデータベースの設定
まず、Airtableでデータベース(ベース)を作成し、必要なテーブルとフィールドを追加しました。この例では、mapInfoという名前のテーブルがあり、以下のフィールドを含んでいます:
areaName:エリアの名称
areaInfo:エリアの情報(例:紹介リンク)
areaImage:エリアの画像(添付ファイルタイプ)
データ構造の定義
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
}
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()
}
}
TableViewの設定
次に、Airtableから取得したデータを表示するためにUITableViewを設定します。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 {
// データを他の処理に使用
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
}
}
TableViewセルの設定
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のデリゲートとデータソースを設定し、データの表示と管理を実現しました。次に、APIのリンクをボタンにしてSafariで表示することに挑戦したいと思います。