Try   HackMD

新人資訊

技術-iOS #7-伸出觸角呼叫 api,存取 GPS,連同 delegate 等技術

本回合所要完成的應用是,取得所在位置資訊,或輸入全球任一個城市的名稱,然後程式透過網路呼叫 openweathermap 提供的 api 取得當時天氣,顯示在 app 畫面上。此單元學到超多東西,如讓 app 可以切換深色模式/淺色模式,protocol (幾乎等同於 interface),delegate design pattern,closure (類似匿名函數),extension,呼叫 api,解析 json 物件,最後連 GPS 抓位置的方法也搞定了,真是太大包了,學得太過癮了,先下載專案框架:https://github.com/appbrewery/Clima-iOS13 稍微看一下 UI 佈局。

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

首先登場的名詞是 protocol,聽了好久後來才發現其實是原來所慣用的 interface;一般的 protocol 是沒有任何實作的,只規定必須實作的方法規格,但此專案使用到系統內建的 protocol 時卻發現不實作也不會有錯誤,這令我困惑很久!後來才發現原來 protocol 可以透過 extension 去定義預設的實作!extension 功能非常強大,也可以用在延伸既有的 class or struct。

另一個名詞為 closure,剛聽時真是一頭霧水,原來就是一個「匿名函數」,不同於習慣的 lumbda 語法,變成怪怪的一整個不習慣,在此筆記一下:https://docs.swift.org/swift-book/LanguageGuide/Closures.html 相信 apple 的設計水準,應該很快就會習慣。

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

然後一個重要的觀念 delegate design pattern 登場,這個已經融入各語言的基本組成了,雖然以前用過,但都是胡亂 google 依樣葫蘆,總覺得觀念似懂非懂,這次認真跟著講師重頭開始手把手一邊實作一邊娓娓道來,真的非常受用,再用自己的話筆記下來,希望觀念可以印的更深刻,如以下的例子:

「急救支援服務」是一個 protocal,其中規定必須實作一個方法 performCPR()
「勤務中心」是一個 class,裡面有一個欄位稱為 delegate,其型別為「急救支援服務」;另外有許多任務需要執行,其中有用到 CPR 的部分直接呼叫 delegate?.performCPR(),此時並不知道何種實體會執行此動作,但可確保不管任何實體都必須實作「急救支援服務」,因此保證有 performCPR() 這個方法。我想成把急救支援服務外包 (委派) 的意思。
「護理師」是一個 struct,它實作「急救支援服務」這個 protocal,所以它必須實作 performCPR(),而妙的是在護理師的建構子中規定必須傳入參數「勤務中心」也就是護理師依存於一個勤務中心,而把勤務中心裡面的 delegate 設成自己!這就是奇妙的有點詭異的地方!對比於護理師,可以建立另一個 struct「醫師」擔任同要角色。
以上為設計和定義的部分,下面開始引用之讓系統運作起來:
「台北醫療服務站」是一個勤務中心的實體,「Mary」是一個護理師,當護理師被初始化時傳入「台北醫療服務站」,根據護理師 class 的定義,會把醫療服務站的 delegate 設成自己,此情境可用一句話描述:Mary 護理師到台北醫療服務站上工執勤。依此類推,另一個情境可能是:Peter 醫師到台北醫療服務站執勤。對台北醫療服務站而言只管執行日常勤務,其中 performCPR() 是由誰執行它可以不在意,但可保證有人執行,醫療服務站的運作機制也可以重複運用。以上,覺得講師還講得真好。

delegation design pattern 應與到此 app 的用法,體現在關於那個輸入城市名稱的 searchTextField 的驗證處理機制。「驗證機制」在這兒是 UITextFieldDelegate,是一個 protocol,規定必須實作 ShouldReturn, ShouldEndEditing, DidEndEditing 等方法,相當於上述的急救支援服務,這個 ViewController 引用此 protocol 就是使自己成為受訓認證而有驗證能力的專業人士,在他自己初始化時就與它的服務對象 searchTextField 建立關聯成為它裡面的 delegate 欄位,當服務對象需要時 (使用這按下搜尋鍵停止編輯時,或按下虛擬鍵盤 enter 鍵時) 透過 delegate 欄位呼叫執行驗證機制和後續取得天氣資訊的程序。(好拗口,也好漂亮)

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

delegate design pattern 二度使用於「顯示天氣資訊」,包含更新一個圖示和顯示溫度和城市名稱。顯示天氣資訊這種事情需要事先執行耗時的網路傳輸 api 呼叫和 decode JSON 等動作,所以無法由顯示方 (也就是畫面) 主導,所以我們另外建立一個 struct WeatherManager 來主導執行細節,執行完成再「委任」非特定對象執行顯示工作,所以此畫面的 viewController 就是需要引用 protocol 的人,而定義 protocol 則在 WearherManager 裏面:

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

注意到以上 session.dataTask() 後面就是 closure,多看幾次語法也快就習慣了。而 ViewController 部分引用了 extension 功能,不用把一堆程式寫在同一個 class 裡面,而是「擴充」之寫在另一個區塊,這樣的結構看起來非常清晰美觀。

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

關於解析 JSON 的細節,必須觀察 api 回傳的結構,挑出想要的欄位,完全仿照其結構建立一個 struct 如下 WeatherData,若有巢狀結構也必需比照辦理。conditionName 則不在 api 回傳欄位之內,我們自己用 getConditionName() 取得對應 swift 內建的 icon name,要傳回畫面端顯示雲或太陽等圖樣。

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

最後還有一個任務,就是抓到 GPS 資訊定位到及時的經緯度!預計在畫面載入之後隨即啟動模組取得位置,之後也可以在畫面點選按鈕再次執行此程序。

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

與 WeatherManager 完全一樣的作法,再玩一次 delegate,再次 extent ViewController,把自己註冊給 locationManager,在 locationManager 完成定位任務就會透過 delegate 觸發 locationManager(_, didUpdateLocation),在此 _ 代表呼叫方不需指定參數名稱,didUpdateLocation 是 external parameter name,locations 為 inner parameter name,這些都可透過查詢文件得知,寫法很靈活,存在一堆眉角,用慣了應該會很方便。 取得經緯度後就傳給 weatherManager 繼續取得即時天氣的程序。

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

以上終於完成全部拼圖,執行起來如下,簡單幾個動作背後的技術含量真不少啊!

https://youtu.be/-KmyLBNmrWI

By Newman Chen 2022/7/21