【App Dev-SwiftUI心得筆記】#3 以AirTable作為簡單資料庫進行串連API
7 min readMay 21, 2021
Goal: 完成Category Art頁面
Used Tools:
AirTable / URLSession / SDWebimage
製作Category DataBase
在AirTable建立簡易的資料庫,並獲取API格式
建立解析JSON用的protocol型別
使用URLSession 獲取Data,進行JSON解析
將解析後的資料顯示在畫免上
SDWebimage → 用來設定顯示網路上圖片的Library
顯示結果
Clean Code!
DateFromAirtable
struct AirtableRecords:Decodable {
var records : [AirTableRecord]
}
struct AirTableRecord: Decodable,Hashable {
var id : String
var fields : Place
}
struct Place: Decodable,Hashable {
var name,thumbnail : String
}
ActiveIndicatorView
import SwiftUIstruct ActiveIndicatorView: UIViewRepresentable { //製作UIKIT物件
func makeUIView(context: Context) -> UIActivityIndicatorView {
let aiv = UIActivityIndicatorView(style: .large)
aiv.startAnimating()
aiv.color = UIColor.white
return aiv
}
func updateUIView(_ uiView: UIActivityIndicatorView, context: Context) {
}
typealias UIViewType = UIActivityIndicatorView
}struct ActiveIndicatorView_Previews: PreviewProvider {
static var previews: some View {
ActiveIndicatorView()
}
}
CategoryDetialView
import SwiftUIimport SDWebImageSwiftUIclass CaregoryDetialViewModle: ObservableObject {
@Published var isLoading = true///宣告isLoading 狀態 預設為true
@Published var arts = [AirTableRecord]()
@Published var errorMesage = ""
init(){
DispatchQueue.main.asyncAfter(deadline: .now() + 2){
self.isLoading = false
guard let url = URL(string: "<https://api.airtable.com/v0/appUJv9kyMlHpugJ7/Art>") else {
return
}
var request = URLRequest(url: url)
request.setValue("AirTable授權碼", forHTTPHeaderField: "Authorization")
request.httpMethod = "GET"
URLSession.shared.dataTask(with: request) { data, resp, err in
guard let data = data else { return }
do{
let reords = try JSONDecoder().decode(AirtableRecords.self, from: data)
self.arts = reords.records
}
catch{
print("Failed to decode JSON",error)
self.errorMesage = error.localizedDescription
}
}.resume()}
}
}struct CategoryDetialView: View {
@ObservedObject var vm = CaregoryDetialViewModle() /// 宣告VM
var body: some View{
if vm.isLoading == true{
VStack{
ActiveIndicatorView()
Text("loading")
.font(.system(size: 12, weight: .semibold))
.foregroundColor(.white)
}
.padding()
.background(Color.black)
.cornerRadius(6)
}else{
ZStack{
Text(vm.errorMesage)
ScrollView(.vertical){
VStack(spacing: 12){
ForEach(vm.arts, id: \\.self) { art in
VStack{
WebImage(url: URL(string: art.fields.thumbnail))
.resizable()
.scaledToFill()
.clipped()
.frame(height: 200)
HStack{
Text(art.fields.name)
.font(.system(size: 14, weight: .semibold))
Spacer()
}
.padding()
.background(Color.white)
}
.asTile()
}
}.padding(.horizontal)
.padding(.top)
}
}
.navigationBarTitle("Category", displayMode: .inline)
}
}
}struct CategoryDetialView_Previews: PreviewProvider {
static var previews: some View {
NavigationView{
CategoryDetialView()
}
}
}