--- tags: 新人資訊 GA: G-YWCCFEGXSJ --- [新人資訊](https://hackmd.io/@newman/portal-info) # 技術-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 佈局。 ![](https://newprediction.blob.core.windows.net/notebook-img/JRcxsD7.png) 首先登場的名詞是 protocol,聽了好久後來才發現其實是原來所慣用的 interface;一般的 protocol 是沒有任何實作的,只規定必須實作的方法規格,但此專案使用到系統內建的 protocol 時卻發現不實作也不會有錯誤,這令我困惑很久!後來才發現原來 protocol 可以透過 extension 去定義預設的實作!extension 功能非常強大,也可以用在延伸既有的 class or struct。 另一個名詞為 closure,剛聽時真是一頭霧水,原來就是一個「匿名函數」,不同於習慣的 lumbda 語法,變成怪怪的一整個不習慣,在此筆記一下:https://docs.swift.org/swift-book/LanguageGuide/Closures.html 相信 apple 的設計水準,應該很快就會習慣。 ![](https://newprediction.blob.core.windows.net/notebook-img/156yXMB.png) 然後一個重要的觀念 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 欄位呼叫執行驗證機制和後續取得天氣資訊的程序。(好拗口,也好漂亮) ![](https://newprediction.blob.core.windows.net/notebook-img/YN4UwEH.png) delegate design pattern 二度使用於「顯示天氣資訊」,包含更新一個圖示和顯示溫度和城市名稱。顯示天氣資訊這種事情需要事先執行耗時的網路傳輸 api 呼叫和 decode JSON 等動作,所以無法由顯示方 (也就是畫面) 主導,所以我們另外建立一個 struct WeatherManager 來主導執行細節,執行完成再「委任」非特定對象執行顯示工作,所以此畫面的 viewController 就是需要引用 protocol 的人,而定義 protocol 則在 WearherManager 裏面: ![](https://newprediction.blob.core.windows.net/notebook-img/9GpKyrK.png) 注意到以上 session.dataTask() 後面就是 closure,多看幾次語法也快就習慣了。而 ViewController 部分引用了 extension 功能,不用把一堆程式寫在同一個 class 裡面,而是「擴充」之寫在另一個區塊,這樣的結構看起來非常清晰美觀。 ![](https://newprediction.blob.core.windows.net/notebook-img/po8yA5I.png) 關於解析 JSON 的細節,必須觀察 api 回傳的結構,挑出想要的欄位,完全仿照其結構建立一個 struct 如下 WeatherData,若有巢狀結構也必需比照辦理。conditionName 則不在 api 回傳欄位之內,我們自己用 getConditionName() 取得對應 swift 內建的 icon name,要傳回畫面端顯示雲或太陽等圖樣。 ![](https://newprediction.blob.core.windows.net/notebook-img/iWpYSXy.png) ![](https://newprediction.blob.core.windows.net/notebook-img/lqDaEMD.png) 最後還有一個任務,就是抓到 GPS 資訊定位到及時的經緯度!預計在畫面載入之後隨即啟動模組取得位置,之後也可以在畫面點選按鈕再次執行此程序。 ![](https://newprediction.blob.core.windows.net/notebook-img/6lZg5Cp.png) 與 WeatherManager 完全一樣的作法,再玩一次 delegate,再次 extent ViewController,把自己註冊給 locationManager,在 locationManager 完成定位任務就會透過 delegate 觸發 locationManager(_, didUpdateLocation),在此 _ 代表呼叫方不需指定參數名稱,didUpdateLocation 是 external parameter name,locations 為 inner parameter name,這些都可透過查詢文件得知,寫法很靈活,存在一堆眉角,用慣了應該會很方便。 取得經緯度後就傳給 weatherManager 繼續取得即時天氣的程序。 ![](https://newprediction.blob.core.windows.net/notebook-img/jm186jb.png) 以上終於完成全部拼圖,執行起來如下,簡單幾個動作背後的技術含量真不少啊! https://youtu.be/-KmyLBNmrWI By Newman Chen 2022/7/21