最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網(wǎng) 會員登陸 & 注冊

SwiftUI學(xué)習(xí)100天(Day68 - 項目 14,第一部分)

2023-03-13 12:00 作者:愛上樹の蝸牛  | 我要投稿

原創(chuàng)鏈接:https://www.hackingwithswift.com/100/swiftui

以下內(nèi)容僅供學(xué)習(xí)參考:

你會很高興知道今天是你一段時間以來最輕松的一天。這并不意味著我們正在研究不重要的東西,只是我們所涵蓋的新技術(shù)幾乎可以保證是你最近不得不面對的協(xié)調(diào)器、選擇器和更多東西的可喜突破。

我所能做的就是:在它持續(xù)的時候享受它!明天我們將回到困難的部分,鑒于你在這 100 天內(nèi)已經(jīng)超過三分之二大關(guān),我希望這不會讓人感到意外。

繼續(xù)前進!正如文斯·隆巴爾迪 (Vince Lombardi) 所說,“字典里只有成功先于工作的地方?!?/p>

今天你有四個主題要完成,你將在其中學(xué)習(xí)如何實現(xiàn)Comparable、查找用戶的文檔目錄等。

愿望清單:簡介

在這個項目中,我們將構(gòu)建一個應(yīng)用程序,讓用戶可以在地圖上構(gòu)建他們打算某天訪問的地點的私人列表,為該地點添加描述,查找附近有趣的地點,并保存它全部到 iOS 存儲以備后用。

要使所有這些工作正常進行,將意味著利用你已經(jīng)掌握的一些技能,例如表單、工作表、CodableURLSession,但也會教給你一些新技能:如何在 SwiftUI 應(yīng)用程序中嵌入地圖,如何安全地存儲私有數(shù)據(jù),以便只有經(jīng)過身份驗證的用戶才能訪問它,如何在 UserDefaults之外加載和保存數(shù)據(jù),等等。

因此,有很多東西要學(xué)習(xí),還有另一個很棒的應(yīng)用程序要制作!不管怎樣,讓我們開始使用我們的技術(shù):使用 App 模板創(chuàng)建一個新的 iOS 項目,并將其命名為 BucketList?,F(xiàn)在開始我們的技術(shù)……


為自定義類型添加對 Comparable 的一致性

仔細(xì)想想,當(dāng)我們編寫 Swift 代碼時,我們認(rèn)為很多東西都是理所當(dāng)然的。例如,如果我們寫4 < 5,我們希望它返回真——Swift(和 LLVM,Swift 背后更大的編譯器項目)的開發(fā)者已經(jīng)完成了檢查該計算是否真實的所有艱苦工作,所以我們不不必?fù)?dān)心。

但 Swift真正擅長的是使用協(xié)議和協(xié)議擴展將功能擴展到很多地方。例如,我們知道這4 < 5是真的,因為我們能夠比較兩個整數(shù)并確定第一個整數(shù)是在第二個整數(shù)之前還是之后。Swift 將該功能擴展到整數(shù)數(shù)組:我們可以比較數(shù)組中的所有整數(shù)來決定每個整數(shù)應(yīng)該在其他整數(shù)之前還是之后。Swift 然后使用該結(jié)果對數(shù)組進行排序。

所以,在 Swift 中,我們希望這種代碼能夠正常工作:

我們不需要告訴sorted()它應(yīng)該如何工作,因為它了解整數(shù)數(shù)組的工作方式。

現(xiàn)在考慮這樣一個結(jié)構(gòu)體:

我們可以將這些用戶組成一個數(shù)組,并在List這樣的內(nèi)部使用它們

那會工作得很好,因為我們使User結(jié)構(gòu)符合Identifiable.

但是如果我們想按排序順序顯示這些用戶呢?如果我們將代碼修改成這樣,它將不起作用:

Swift 不明白sorted()這里的意思,因為它不知道是按名字、姓氏、兩者還是其他方式排序。

之前我向你展示了我們?nèi)绾翁峁┮粋€閉包來讓sorted()自己進行排序,我們可以在這里使用相同的方法:

這絕對有效,但由于兩個原因,它不是理想的解決方案。

首先,這是模型數(shù)據(jù),我的意思是它會影響我們使用User結(jié)構(gòu)的方式。該結(jié)構(gòu)及其屬性是我們的數(shù)據(jù)模型,在一個開發(fā)良好的應(yīng)用程序中,我們真的不想告訴模型它在我們的 SwiftUI 代碼中應(yīng)該如何表現(xiàn)。SwiftUI 代表我們的視圖,即我們的布局,如果我們將模型代碼放在那里,事情就會變得混亂。

其次,如果我們想User在多個地方對數(shù)組進行排序會怎樣?你可能會復(fù)制并粘貼一次或兩次閉包,然后才意識到你只是在給自己制造一個問題:如果你最終更改了排序邏輯以便firstName在姓氏相同時也使用,那么你需要搜索你所有的代碼以確保所有閉包都得到更新。

Swift 有更好的解決方案。整數(shù)數(shù)組有一個沒有參數(shù)的簡單sorted()方法,因為 Swift 知道如何比較兩個整數(shù)。在編碼術(shù)語中,Int符合Comparable協(xié)議,這意味著它定義了一個函數(shù),該函數(shù)接受兩個整數(shù)并在第一個應(yīng)該排在第二個之前返回 true。

我們可以讓我們自己的類型符合Comparable,當(dāng)我們這樣做時,我們也會得到一個sorted()沒有參數(shù)的方法。這需要兩個步驟:

  1. Comparable一致性添加到 User的定義中。

  2. 添加一個名為的方法,該方法<需要兩個用戶,如果第一個用戶應(yīng)該排在第二個用戶之前,則返回 true。

這是代碼中的樣子:

里面的代碼不多,但是還是有很多要展開的。

首先,是的,該方法只是被調(diào)用<,這是“小于”運算符。確定一個用戶是否“小于”(在排序意義上)另一個用戶是該方法的工作,因此我們正在向現(xiàn)有運算符添加功能。這稱為運算符重載,它既是福也是禍。

其次,lhsrhs是“左手邊”和“右手邊”的縮寫,使用它們是因為<運算符在其左側(cè)和右側(cè)有一個操作數(shù)。

第三,這個方法必須返回一個布爾值,這意味著我們必須決定一個對象是否應(yīng)該排在另一個對象之前。這里沒有“它們相同”的余地——這是由另一個名為Equatable.

第四,該方法必須標(biāo)記為static,這意味著它是User直接在結(jié)構(gòu)上調(diào)用的,而不是結(jié)構(gòu)的單個實例。

最后,我們的邏輯非常簡單:我們只是將比較傳遞給我們的一個屬性,要求 Swift 將其<用于兩個姓氏字符串。你可以根據(jù)需要添加任意多的邏輯,根據(jù)需要比較任意多的屬性,但最終你需要返回 true 或 false。

提示:你在該代碼中看不到的一件事是,符合Comparable也使我們能夠訪問>運算符 – 大于。這與 <相反,因此 Swift 通過使用布爾值并在 true 和 false 之間翻轉(zhuǎn)<來為我們創(chuàng)建它。

現(xiàn)在我們的User結(jié)構(gòu)符合Comparable,我們自動獲得了無參數(shù)版本的訪問權(quán)限sorted(),這意味著這種代碼現(xiàn)在可以工作了:

這解決了我們之前遇到的問題:我們現(xiàn)在將我們的模型功能隔離在結(jié)構(gòu)本身中,我們不再需要復(fù)制和粘貼代碼——我們可以sorted()在任何地方使用,安全地知道如果我們改變算法那么我們所有的代碼會適應(yīng)。


將數(shù)據(jù)寫入文檔目錄

之前我們研究了如何讀取和寫入數(shù)據(jù)UserDefaults,這對于用戶設(shè)置或少量 JSON 非常有用。但是,它通常不是存儲數(shù)據(jù)的好地方,尤其是當(dāng)你認(rèn)為將來會開始存儲更多數(shù)據(jù)時。

在此應(yīng)用程序中,我們將允許用戶創(chuàng)建他們想要的盡可能多的數(shù)據(jù),這意味著我們需要一個更好的存儲解決方案,而不是僅僅將東西扔進去UserDefaults并希望最好的。幸運的是,iOS 使得從設(shè)備存儲中讀取和寫入數(shù)據(jù)變得非常容易,事實上所有應(yīng)用程序都有一個目錄來存儲我們想要的任何類型的文檔。這里的文件自動與 iCloud 備份同步,因此如果用戶獲得新設(shè)備,我們的數(shù)據(jù)將與所有其他系統(tǒng)數(shù)據(jù)一起恢復(fù)——我們甚至不需要考慮它。

有一個陷阱——不是總是有嗎?– 而且所有 iOS 應(yīng)用程序都是沙盒化的,這意味著它們在自己的容器中運行,目錄名稱難以猜測。因此,我們不能——也不應(yīng)該嘗試——猜測我們應(yīng)用程序的安裝目錄,而是需要依賴 Apple 的 API 來查找我們應(yīng)用程序的文檔目錄。

沒有什么好的方法可以做到這一點,所以我?guī)缀蹩偸菍⑾嗤妮o助方法復(fù)制并粘貼到我的項目中,我們現(xiàn)在將做完全相同的事情。這使用了一個名為 FileManager的新類,它可以為我們提供當(dāng)前用戶的文檔目錄。理論上這可以返回多個路徑 URL,但我們只關(guān)心第一個。

因此,將此方法添加到ContentView

該文檔目錄是我們的,可以隨心所欲地處理,因為它屬于應(yīng)用程序,所以如果應(yīng)用程序本身被刪除,它會自動被刪除。除了物理設(shè)備限制外,我們可以存儲多少沒有限制,但請記住,用戶可以使用“設(shè)置”應(yīng)用程序查看你的應(yīng)用程序占用了多少存儲空間——請尊重!

現(xiàn)在我們有了一個可以使用的目錄,我們可以在那里自由地讀寫文件。你已經(jīng)遇到了String(contentsOf:)Data(contentsOf:)用于讀取數(shù)據(jù)的方法,但是對于寫入數(shù)據(jù)我們需要使用該write(to:)方法。當(dāng)與字符串一起使用時,這需要三個參數(shù):

  1. 寫給一個URL。

  2. 是否使寫入成為原子的,這意味著“一次全部”。

  3. 使用什么字符編碼。

第一個可以通過將文檔目錄 URL 與文件名組合來創(chuàng)建,例如 myfile.txt。

第二個應(yīng)該幾乎總是設(shè)置為真。如果將其設(shè)置為 false 并且我們嘗試寫入一個大文件,則我們應(yīng)用程序的另一部分可能會在文件仍在寫入時嘗試讀取該文件。這不應(yīng)該導(dǎo)致崩潰或任何事情,但它確實意味著它將只讀取部分?jǐn)?shù)據(jù),因為另一部分尚未寫入。原子寫入導(dǎo)致系統(tǒng)將我們的完整文件寫入一個臨時文件名(不是我們要求的那個),完成后它會簡單地重命名為我們的目標(biāo)文件名。這意味著要么整個文件都存在,要么什么都沒有。

第三個參數(shù)是我們在項目 5 中簡要查看的內(nèi)容,因為我們必須使用帶有 Objective-C API 的 Swift 字符串。那時我們使用字符編碼 UTF-16,這是 Objective-C 使用的,但 Swift 的本機編碼是 UTF-8,所以我們將改用它。

為了將所有這些代碼付諸實踐,我們將修改模板的默認(rèn)文本視圖,以便將測試字符串寫入文檔目錄中的文件,將其讀回新字符串,然后將其打印出來——完整的數(shù)據(jù)讀寫周期。

ContentViewbody屬性更改為此:

當(dāng)它運行時,你應(yīng)該能夠點擊標(biāo)簽以查看打印到 Xcode 的調(diào)試輸出區(qū)域的“測試消息”。

在我們繼續(xù)之前,這里有一個小挑戰(zhàn):回到項目 8,我們研究了如何創(chuàng)建一個通用擴展Bundle,讓我們從我們的應(yīng)用程序包中查找、加載和解碼任何Codable數(shù)據(jù)。你能否為文檔目錄編寫類似的內(nèi)容,也許使其成為 FileManager的擴展名


使用枚舉切換視圖狀態(tài)

你已經(jīng)了解了我們?nèi)绾问褂贸R?guī) Swift 條件來呈現(xiàn)一種或另一種類型的視圖,并且我們查看了如下代碼:

提示:返回不同類型的視圖時,請確保你在body屬性內(nèi)部或使用類似@ViewBuilderGroup的內(nèi)容。

條件視圖特別有用的地方是當(dāng)我們想要顯示幾種不同狀態(tài)之一時,如果我們正確地計劃它,我們可以保持我們的視圖代碼小并且易于維護——這是開始訓(xùn)練你的大腦思考 SwiftUI 的好方法建筑學(xué)。

這個解決方案有兩個部分。第一個是為你要表示的各種視圖狀態(tài)定義一個枚舉。例如,你可以將其定義為嵌套枚舉:

接下來,為這些狀態(tài)創(chuàng)建單獨的視圖。我將在這里使用簡單的文本視圖,但它們可以容納任何東西:

如果你愿意,這些視圖可以嵌套,但它們不一定是 - 這實際上取決于你是否打算在其他地方使用它們以及你的應(yīng)用程序的大小。

有了這兩個部分,我們現(xiàn)在可以有效地將ContentView用作跟蹤當(dāng)前應(yīng)用程序狀態(tài)并顯示相關(guān)子視圖的簡單包裝器。這意味著給它一個屬性來存儲當(dāng)前LoadingState值:

然后body中添加代碼,根據(jù)枚舉的值顯示正確的視圖,如下所示:

使用這種方法,我們的ContentView不會隨著越來越多的代碼被添加到視圖中而失控,事實上,我們甚至不知道加載、成功或失敗是什么樣子。




SwiftUI學(xué)習(xí)100天(Day68 - 項目 14,第一部分)的評論 (共 條)

分享到微博請遵守國家法律
馆陶县| 玉林市| 罗江县| 青河县| 绥棱县| 绥中县| 砀山县| 双峰县| 凤阳县| 泰州市| 万全县| 锦州市| 江阴市| 汶上县| 龙江县| 英吉沙县| 宁明县| 贡山| 绥江县| 通山县| 平定县| 富蕴县| 克什克腾旗| 上林县| 和龙市| 沾化县| 大名县| 苏尼特左旗| 龙门县| 宝坻区| 邯郸县| 乌兰察布市| 鄯善县| 太湖县| 弥渡县| 阳城县| 清镇市| 海宁市| 东源县| 个旧市| 丹凤县|