15. %d\n Xcode Study— About Design Pattern 由繁入簡(ㄧ)

春麗 S.T.E.M.
9 min readAug 22, 2021

--

解析本地JSON File / 解析網路API (Airtable上傳讀取) /postman/使用土法

這篇參照了raywenderlich上的MVC模型,並加入了網路功能做練習。

這個土法裡包含兩種tableview cell,一個是自設計,一個是內建的。由下圖可見,有三個viewcontroller,兩個model,所以我們知道所有要做的事情全部塞在controller裡,包含了宣告變數、設計方法(與網路、本地資料交互、處理顯示數值)、顯示UI元件、顯示view、傳值(segueAction)等。

session對應到的是json檔案,即是本地資料;attendee對應到的是airtable的資料,即是網路資料。

session
fetchData、tableViewCell

為了解析json,需設置與json內容裡與key相同名稱的struct屬性

本地資料僅需從bundle去讀取檔案名副檔名,若屬性有Date型別,還需輔以DateFormatter,設置好時間格式解碼策略,便是一般流程的try data與try decode,將解出來的東西賦值給var sessions = [Session]()。

cell的主要datasource流程為,找到該cell ID的cell,將裡面的ui元件賦值,若有date型別要顯示,一樣用DateFormatter,設置時間格式,轉為字串,最後再給元件。

接著是attendee

光看表單資料未必能夠明白為什麼結構要如圖右般宣告,改以使用表單名稱獲得的api位址,丟到postman看看

物件第一層為records,對應的value為陣列,該陣列第一層( 物件第二層 )為id與fields,id可視為每一筆資料分配的一個識別碼,fields裡面才是我們要的屬性。

那麼自訂型別Attendee裡,第一個變數也是records,讓它型別是下一層型別的陣列,所以很自然地,let records = [Record],Record裡包著id與fields,但我們未必需要id,所以直接略過它,只宣告let fields: Fields,由於fields對應到的是物件,不是陣列,所以對應到Fields型別。

終於,最後一個struct Fields裡面包著我們要的key & value,然而,不能將它視為你原先輸入的的型別,由於它的value都用” ”包著,所以都是String。

接著是獲取檔案設置cell

網路資料從網址開始,將string轉換為url後,需搭配request,以api key發送請求,api key如同憑證,也像github的token,接著httpMethod為GET,小寫也行。(預設為GET,所以如果是GET,這行也可以不寫)

由於是網路資料,便要使用URLSession,一開始,為了確定有沒有正確獲取資料,可以這樣寫

if let data = data, let content = String(data: data, encoding: .utf8) { print(content) }

看看debug區有沒有印出內容。由於這邊不需要解析Date,所以只需要JSONDecoder,而session前面做了那麼多事,就是為了知道裡面有沒有data,直接以if let data = data 去寫{ }裡的,do & catch,不需要像本地資料要多try一個Data(contentOf: url)去取得data,才能解析成自己的型別。

guard let else { return },在使用上也需要小心,雖然不會讓程式死掉,但有時沒設置檢查,會不知道錯誤在哪裡,即是安全地什麼訊息也沒也不好。

在cell的地方,會這樣宣告變數 var attendee = Attendee(records: [])

由於records是結構裡面的變數(即屬性),並非另一個型別,所以宣告時,它會包在最外層結構裡作為參數,它是一個陣列,宣告為空陣列。

當屬性已被賦值後,cell是預設樣式,cell兩邊的label是textLabeldetailTextLabel。且這個預設的cell只需要設置cell ID,當使用dequeReusable時,不再需要轉型為特定的cell class,即是它也毋需繼承。

再來先對比看看,上傳資料是怎麼寫的

前面完全一樣,但從”POST”後就有些許不同

  1. 需要setValue,content-type為json。
  2. 使用JSONEncoder。
  3. 嘗試解析欲加入的內容,將之賦值給httpBody。

有趣的是,此刻轉頭去解析,或者讀檔,會得到的都是你加入的那個檔案,如果是”GET”,會得到所有內容。

稍作整理,URLSession是swift用來做網路連線的一個class,無論生成一個task實體,或直接使用它,最後都要記得resume( )

關於URL,繞道使用request,才能與airtable交互(增刪修讀),否則一般情況下,本地json只要用bundle取得的url,便可try Data後去解析data為自訂型別;或字串位址轉換為url,便可去解析data為自訂型別。

關於連線,可用response的statusCode去檢查網路狀態,例如200是正常連線,404、500是錯誤等。

      guard let response = response as? HTTPURLResponse, response.statusCode == 200 else { return }

當過了response關卡,解析前,可印出內容來看看POST或GET是如何。

      if let data = data, let content = String(data: data, encoding: .utf8) { print(content) }

總之,POST了,就得到多的一筆資料

這邊特別提醒,如果去修改表格名稱,它的API位址也同樣會改變,於是,程式裡的url便要一起修改。

最後一步是傳值,新增的屬性分別為兩個頁面要傳值到下一頁的值,可見是字串與字串插值的組合。

在Detail頁,我們希望viewWillAppear時,就幫我們設定好textView的text。

你能看出左邊是session的segueAction,右邊是attendee的嗎?不能,因為根本一模一樣,這也就是在之後,我們還是要來重構程式碼。

開始練習時,可能會將model與viewcontroller擺在一起,宣告在class上面,如今已習慣model跟controller拆開的寫法。

--

--

春麗 S.T.E.M.
春麗 S.T.E.M.

Written by 春麗 S.T.E.M.

Do not go gentle into that good night, Old age should burn and rave at close of day; Rage, rage, against the dying of the light.

No responses yet