技術筆記-iOS實戰002-搞定 api 非同步呼叫,json 解碼,和一些檔案儲存的事

更新於 2024/06/20閱讀時間約 10 分鐘

需求情境:

在設計畫面時,資料來源是後台的 api,每一次畫面細節的修修改改,都會觸發 Xcode Preview 程序,導致不斷呼叫後台。此時若資料結構和大小都具有一定規模,就會導致效率低落,不斷等待,且消耗伺服器資源甚鉅。

每次畫面一點的小修改,都會觸發 preview 重跑

每次畫面一點的小修改,都會觸發 preview 重跑


解決方案:

將後台傳回的資料以檔案形式暫存在本地端,每次 preview 都呼叫本地端檔案以節省時間和資源。再加上一個配套措施,就是由一個按鈕,觸發真正呼叫後台的程序,而呼叫後順便更新本地端檔案。以下開始實作。


實作步驟:

首先探討呼叫 api 的程序,檢討上一篇「iOS實戰001」所提的方法,有一個缺點,就是程序和 UI 元件混在一起,導致呼叫邏輯無法抽離到另一個檔案。因爲這是專案中經常會用到的通用程序,抽離才可以更好的共用,所以改用 async await 語法改寫,讓程序傳回通用型別 (Data) 的值:

func fetchApiDataAsync(urlString: String) async throws -> Data {
    guard let url = URL(string: urlString)
    else {
        throw MyError.error1
    }
    let (data, response) = try await URLSession.shared.data(from: url)
    guard let httpResponse = response as? HTTPURLResponse, httpResponse.statusCode == 200 else {
        throw MyError.error1
    }
    return data
}

這樣在任何一個畫面需要呼叫後台時,都可以在 onAppear() 事件中執行以下程序,取得資料後再執行與畫面相依的 decode 和 bind。以下 dashItems 就是宣告在畫面的狀態變數:

func getDashItems(urlString: String) {
    Task {
        do {
            let data = try await fetchApiDataAsync(urlString: urlString)
            let decoder = JSONDecoder()
            let dashItems = try decoder.decode([DashItem].self, from: data)                
            self.dashItems = dashItems // 此行把資料 bind 到畫面上
        } catch {
            print("Fail to fetch api data")
        }
    }
}


為了把回傳資料取出,用最原始的文字檔方式儲存在檔案,我們需要把 Data 的內容解開,轉換成為 String,我們把它包裝成另一個 function:

func fetchApiRawDataAsync(urlString: String) async throws -> String {
    guard let url = URL(string: urlString)
    else {
        throw MyError.error1
    }
    let (data, response) = try await URLSession.shared.data(from: url)
    guard let httpResponse = response as? HTTPURLResponse, httpResponse.statusCode == 200 else {
        throw MyError.error1
    }
    let rawString = String(data: data, encoding: .utf8)! // 關鍵是這一行
    return rawString
}


解開 String 之後,就可以存在檔案裡了,檔案儲存的位置有學問。依照 iOS 的運行規則,應用程式只可以把檔案存在一個特殊的資料夾稱為 DocumentDirectory,可用系統內建管理物件 FileManager 取得,我們把它包裝成另一個函數 getDocumentDirectory() ,供儲存檔案的函數呼叫:

func getDocumentDirectory() -> URL {
    let paths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
    return paths[0]
}

func saveDocumentFile(text: String) {
    let fileName = "cache.json"
    let filePath = getDocumentDirectory().appendingPathComponent(fileName)
    do {
        try text.write(to: filePath, atomically: true, encoding: String.Encoding.utf8)
    } catch {
        print("Error when writing file")
    }
}


寫入的檔案到底在哪兒?把路徑印出來長這樣:

file:///Users/newman/Library/Developer/Xcode/UserData/Previews/Simulator%20Devices/4BAD6318-2C87-4437-A00C-7EEFE7ED17F3/data/Containers/Data/Application/F4CC2965-6E39-400C-AA73-DD55FCB18E8C/Documents/cache.json

這雲深不知處的檔案,無法用 finder 查看內容是否正確,就作罷了,因為重點是若可以讀出來就達成目的了,因此先做一個讀出檔案的 function:

func loadDocumentFile(fileName: String) -> String {
    let data: Data
    let filePath = getDocumentDirectory().appendingPathComponent(fileName)
    do {
        data = try Data(contentsOf: filePath)
        return String(data: data, encoding: .utf8)!
    } catch {
        print("Couldn't load \(fileName) from document folder:\n\(error)")
        fatalError("Couldn't load \(fileName) from document folder:\n\(error)")
    }
}


經測試可正常顯示,所以以上會用到的功能都已經備齊了,可由畫面端程式自由組合顯示的邏輯。以下 getDashItemsFromFile() 供每次畫面顯示時呼叫,讀取本地端檔案可以非常快速。另外再加一個 refreshData() 由按鈕觸發,由使用者在必要時執行,呼叫後台並更新本地端檔案:

func getDashItemsFromFile() {
    Task {
        do {
            let rawString = loadDocumentFile(fileName: "cache.json")
            let decoder = JSONDecoder()
            let dashItems = try decoder.decode([DashItem].self, from: Data(rawString.utf8))
            self.dashItems = dashItems
        } catch {
            print("Fail to fetch api data")
        }
    }
}

func refreshData() {
Task {
        do {
            let rawString = try await fetchApiRawDataAsync(urlString: myApiUrl)
            saveDocumentFile(text: rawString)
            let decoder = JSONDecoder()
            let dashItems = try decoder.decode([DashItem].self, from: Data(rawString.utf8))
            self.dashItems = dashItems
        } catch {
            print("Fail to fetch api data")
        }
    }
}
  


Newman 2024/6/14

導覽頁:紐曼的技術筆記-索引


avatar-img
22會員
104內容數
漫步是一種境界。
留言0
查看全部
avatar-img
發表第一個留言支持創作者!
newman的沙龍 的其他內容
Part.1 搞定基本的 UI 開始開發 iOS App。 首先準備一台 Mac,然後安裝 Xcode,新增專案,系統即刻生成基本的專案結構。coding 的起點在檔案 ContentView.swift: import SwiftUI struct ContentView: View {  
技術筆記-用 python 操作 google firestore 的基本方法 (2023/12/26) 技術筆記-以 nodejs 為後台,以 google sheet 充當資料庫 (2022/11/29)
firestore 是 google 所提供的雲端文件式資料庫服務,為各種開發工具提供了方便使用的 sdk,python 的套件名稱為 firebase-admin,用 pip 安裝後就可操作了。 pip install firebase-admin
安裝完成 nodejs 後選用一個工作目錄執行 npm init,npm 會產生一個 package.json 檔案,之後為此專案安裝套件時都會記錄在此,讓專案可以很容易的重建和移植,也可設定 npm start 執行時以哪一個 js 檔當作系統入口。直接開寫了,以下我用 app.js 當作系統入口
首先安裝 python,依照 官網 的指示,下載正確的版本並執行就可,重點在以下。 虛擬環境的管理平台許多人使用 anaconda,許多教 python 的課程第一堂就是不管三七二十一先安裝再說,但我用了一陣子之後覺得它實在太笨重了,早有掙脫的想法,欣見原生的 python 已經具有虛擬環境管理模
Part.1 搞定基本的 UI 開始開發 iOS App。 首先準備一台 Mac,然後安裝 Xcode,新增專案,系統即刻生成基本的專案結構。coding 的起點在檔案 ContentView.swift: import SwiftUI struct ContentView: View {  
技術筆記-用 python 操作 google firestore 的基本方法 (2023/12/26) 技術筆記-以 nodejs 為後台,以 google sheet 充當資料庫 (2022/11/29)
firestore 是 google 所提供的雲端文件式資料庫服務,為各種開發工具提供了方便使用的 sdk,python 的套件名稱為 firebase-admin,用 pip 安裝後就可操作了。 pip install firebase-admin
安裝完成 nodejs 後選用一個工作目錄執行 npm init,npm 會產生一個 package.json 檔案,之後為此專案安裝套件時都會記錄在此,讓專案可以很容易的重建和移植,也可設定 npm start 執行時以哪一個 js 檔當作系統入口。直接開寫了,以下我用 app.js 當作系統入口
首先安裝 python,依照 官網 的指示,下載正確的版本並執行就可,重點在以下。 虛擬環境的管理平台許多人使用 anaconda,許多教 python 的課程第一堂就是不管三七二十一先安裝再說,但我用了一陣子之後覺得它實在太笨重了,早有掙脫的想法,欣見原生的 python 已經具有虛擬環境管理模
你可能也想看
Google News 追蹤
Thumbnail
*合作聲明與警語: 本文係由國泰世華銀行邀稿。 證券服務係由國泰世華銀行辦理共同行銷證券經紀開戶業務,定期定額(股)服務由國泰綜合證券提供。   剛出社會的時候,很常在各種 Podcast 或 YouTube 甚至是在朋友間聊天,都會聽到各種市場動態、理財話題,像是:聯準會降息或是近期哪些科
大家是否有撰寫的心血因為不明原因,網路異常而造成心血全都消失,這篇純粹是一個抒發文...
Thumbnail
提到「做筆記」你會想到什麼?如果說知識的消化可以分為「輸入、處理和輸出」三個階段,那麼你又認為筆記扮演的任務角色會落到哪一個階段?做筆記只是「輸入」成效不高,想要「輸出」又耗時費力。要如何解決這個問題呢?卡片盒筆記法,就是目前最有效的解方,特別是在數位工具智能化之後,更顯得這套方法的強大。
Thumbnail
數位筆記術的改變力量 您有曾經煩惱過學習的效率嗎?或者是覺得難以捕捉那些稍縱即逝的靈感?在我們的日常生活和學習中,這些問題都是常見的挑戰。但幸運的是,有一種工具可以幫助我們改變這些情況,那就是數位筆記術。接下來,我將會講解三個使用數位筆記術的重要原則,這些原則能幫助我們更有效地學習和捕捉靈感。 原則
Thumbnail
《花漾年華》四連幅是我用當代水墨的抽象語彙,表現臺灣春天茂盛的新綠,充滿生命力,山櫻花盛開。傳統花鳥畫的創作哲學是「一花一世界,一葉一如來」,透過描繪大自然的生機呈現藝術家空靈的精神世界,心靈與自然合一,既超越自然又貼近自然。 在手工宣紙,揮灑充滿想像力的純淨世界,留白,紓解現代人過量的影音刺激。
Thumbnail
2014年人生峰迴路轉,從一個藝術愛好者,開始投身書畫創作,九個月後受邀舉辦第一次個展。江心靜透過墨彩融合的技法展現內在生命能量,在堆疊墨韻、鮮明色彩和象徵性符號中,營造藝術與靈性追求的意境,優遊於具象和抽象水墨間。 我用畫畫寫詩,好的詩打破既有窠臼,以全新角度看待人生,詩有無限可能,可以多重解讀。
Thumbnail
藝術家江心靜投入創作第二年,內在巨大無比的能量爆發,完成了 2015《藍色空間》三連幅當代水墨創作。 詩人的心找到了視覺語言,用深邃迷離的藍,與宇宙的能量結合,與早年創作的詩句呼應,內外合一的文人走向天命之路。
Thumbnail
雲海流動如一首神秘的歌,興起一股衝動,想透過創作表達心中感悟,第一個想法是強調「氣韻生動」的水墨,2012年採訪現代水墨之父劉國松,高齡八十的畫家精神奕奕,親自示範技法。 看著成品,在廚房燈下微笑,黑白構成的畫面,有一股力量,從山間飛到城市,推動著自己繼續,不在意繁華如夢,一步一步,往前走。
Thumbnail
兩年多前,開始有了重新架構網站的想法,所以把 Blogger 架設的網站,移轉至到了新的平台,當年我也做過了一些優缺點評析,剛好最近又再重新整理網站的所有架構,順便也重新啟動了一次 Hugo 架設網站的循環。
Thumbnail
因為要轉換一份新工作,認為自己在工作上必需更提高效率,剛好週圍有些朋友使用電子筆記,對於喜歡寫紙本筆記的人來說,是一個新的嘗試,原因有二:其一,筆記上有很多資料,在用完整本筆記之後,隨之石沉大海;其二,現在越來越多資訊是透過網路傳送,如果沒有好好收藏,資料就"放在"硬碟內了。 我是先去Youtube
Thumbnail
*合作聲明與警語: 本文係由國泰世華銀行邀稿。 證券服務係由國泰世華銀行辦理共同行銷證券經紀開戶業務,定期定額(股)服務由國泰綜合證券提供。   剛出社會的時候,很常在各種 Podcast 或 YouTube 甚至是在朋友間聊天,都會聽到各種市場動態、理財話題,像是:聯準會降息或是近期哪些科
大家是否有撰寫的心血因為不明原因,網路異常而造成心血全都消失,這篇純粹是一個抒發文...
Thumbnail
提到「做筆記」你會想到什麼?如果說知識的消化可以分為「輸入、處理和輸出」三個階段,那麼你又認為筆記扮演的任務角色會落到哪一個階段?做筆記只是「輸入」成效不高,想要「輸出」又耗時費力。要如何解決這個問題呢?卡片盒筆記法,就是目前最有效的解方,特別是在數位工具智能化之後,更顯得這套方法的強大。
Thumbnail
數位筆記術的改變力量 您有曾經煩惱過學習的效率嗎?或者是覺得難以捕捉那些稍縱即逝的靈感?在我們的日常生活和學習中,這些問題都是常見的挑戰。但幸運的是,有一種工具可以幫助我們改變這些情況,那就是數位筆記術。接下來,我將會講解三個使用數位筆記術的重要原則,這些原則能幫助我們更有效地學習和捕捉靈感。 原則
Thumbnail
《花漾年華》四連幅是我用當代水墨的抽象語彙,表現臺灣春天茂盛的新綠,充滿生命力,山櫻花盛開。傳統花鳥畫的創作哲學是「一花一世界,一葉一如來」,透過描繪大自然的生機呈現藝術家空靈的精神世界,心靈與自然合一,既超越自然又貼近自然。 在手工宣紙,揮灑充滿想像力的純淨世界,留白,紓解現代人過量的影音刺激。
Thumbnail
2014年人生峰迴路轉,從一個藝術愛好者,開始投身書畫創作,九個月後受邀舉辦第一次個展。江心靜透過墨彩融合的技法展現內在生命能量,在堆疊墨韻、鮮明色彩和象徵性符號中,營造藝術與靈性追求的意境,優遊於具象和抽象水墨間。 我用畫畫寫詩,好的詩打破既有窠臼,以全新角度看待人生,詩有無限可能,可以多重解讀。
Thumbnail
藝術家江心靜投入創作第二年,內在巨大無比的能量爆發,完成了 2015《藍色空間》三連幅當代水墨創作。 詩人的心找到了視覺語言,用深邃迷離的藍,與宇宙的能量結合,與早年創作的詩句呼應,內外合一的文人走向天命之路。
Thumbnail
雲海流動如一首神秘的歌,興起一股衝動,想透過創作表達心中感悟,第一個想法是強調「氣韻生動」的水墨,2012年採訪現代水墨之父劉國松,高齡八十的畫家精神奕奕,親自示範技法。 看著成品,在廚房燈下微笑,黑白構成的畫面,有一股力量,從山間飛到城市,推動著自己繼續,不在意繁華如夢,一步一步,往前走。
Thumbnail
兩年多前,開始有了重新架構網站的想法,所以把 Blogger 架設的網站,移轉至到了新的平台,當年我也做過了一些優缺點評析,剛好最近又再重新整理網站的所有架構,順便也重新啟動了一次 Hugo 架設網站的循環。
Thumbnail
因為要轉換一份新工作,認為自己在工作上必需更提高效率,剛好週圍有些朋友使用電子筆記,對於喜歡寫紙本筆記的人來說,是一個新的嘗試,原因有二:其一,筆記上有很多資料,在用完整本筆記之後,隨之石沉大海;其二,現在越來越多資訊是透過網路傳送,如果沒有好好收藏,資料就"放在"硬碟內了。 我是先去Youtube