實戰教程·元宇宙來了,準備好你的電子名片了嗎?(五)
theme: smartblue
前提回顧
在前幾個章節中,我們已經完成了Linkworld的基本功能,但要達到最小MVP產品還有些距離。完成的功能目前只能在模擬器中使用,缺少本地化儲存、網路請求和編輯、刪除等功能,這尚未達到最小MVP的要求。
MVP是最小的可用產品,其核心在於最小和可用。“最小”代表著該產品可以反覆迭代且迭代週期短,“可用”代表該產品是可以滿足使用者預期的可以交付的產品,而不僅僅是demo。
因此我們繼續深入完善Linkworld這款產品,實現最小MVP產品。
MVVM架構模式:Model-View-ViewModel
通常在SwiftUi開發過程中,開發者們會使用MVVM開發架構模式進行專案搭建。MVVM全稱為Model-View-ViewModel,即模型-檢視-檢視模型。在該架構模式中,我們建立資料模型將資料進行抽象和分離,然後單獨建立檢視,最後使用ViewModel進行雙向繫結連結資料和檢視。
在本專案中,我們建立的Model檔案便是Model模型部分,而ContentView、NewView、HomePageView是View檢視部分,而我們實現的單獨抽離ViewModel模型檢視部分內容,因此在檢視與檢視之間,檢視與模型之間都建立了多次的變數宣告和雙向繫結,示例:indexURL。
下面我們來建立ViewModel檢視模型並在該專案中使用它,建立一個新的Swift檔案,命名為ViewModel,如下圖所示:
為了便於檔案管理,我們可以建立對應的資料夾用於存放不同內容的檔案,使得檔案目錄更加清晰明瞭,如下圖所示:
ViewModel模型檢視檔案作為連結資料模型和檢視之前的“聯絡官”,需要給檢視傳遞來自於Model的資料,因此我們可以建立一個結構體,遵循ObservableObject協議,ObservableObject協議可以在資料更新時通知檢視更新內容。
然後在ViewModel模型檢視內,我們使用建立釋出器來建立來自Model的陣列結構,如下程式碼所示:
``` import Foundation import SwiftUI
class ViewModel:ObservableObject { @Published var models = Model
} ```
URLSession例項:建立網路請求
建立好ViewModel模型檢視後,我們來學習使用URLSession建立一個網路請求,在學習之前我們先來了解一個JSON檔案的相關知識。
JSON是一種檔案格式,和TXT文字一樣,JSON使用帶有固定格式的純文字建立資料集。我們在搭建NewView新增身份卡檢視時曾實現了新增身份卡的方法,即賦值給符合Model格式的變數,然後將Model格式的資料新增到個人主頁的List中。
JSON檔案則是包含了所有符合Model格式的資料的陣列集合,我們可以建立好一個JSON檔案及其內容,並通過網路請求將JSON檔案請求到本地並解析載入到List中。
我們先來看看JSON檔案的格式,如下圖所示:
[
{
"platformIcon": "icon_juejin",
"title": "掘金簽約作者",
"platformName": "稀土掘金技術社群",
"indexURL": "juejin.cn/user/3897092103223517"
},
{
"platformIcon": "icon_aliyun",
"title": "專家博主",
"platformName": "阿里雲社群",
"indexURL": "developer.aliyun.com/profile/expert/376pj7xeqgqjy"
}
]
上述JSON檔案是通過一個線上JSON檔案生成器(如npoint.io、fastmock.site等等)生成的準備程式碼,其中由“[]”包裹的是陣列,而“{}”包裹的是陣列中的物件,我們建立了2個物件,且資料模型格式都符合Model資料模型定義的引數。
通過第三方網站可以生成一個API介面的連結地址,我們宣告一個常量引數儲存它,如下程式碼所示:
let JsonURL = "http://api.npoint.io/c51968c99a2a087dac5e"
當然,我們也可以使用測試工具測試建立的JSON檔案地址返回的結果是否正確,可以使用postman或者apifox測試軟體進行測試,避免在專案開發時請求資料失敗而導致開發卡點的問題,如下圖所示:
上圖中,使用的測試工具是apifox。使用方法也很簡單,建立一個介面並將剛剛生成的地輸入進去,並設定好對應的Query引數,點選執行,便可檢視該介面返回狀態及結果。熟練使用介面測試工具,可以幫助我們節省開發時間。
迴歸正題,我們在ViewModel檢視模型中使用URLSession例項建立一個網路請求的方法,如下程式碼所示:
//網路請求
func getData() {
let session = URLSession(configuration: .default)
session.dataTask(with: URL(string: JsonURL)!) { data, _, _ in
guard let jsonData = data else { return }
do {
let data = try JSONDecoder().decode([Model].self, from: jsonData)
self.models = data
} catch {
print(error)
}
}
.resume()
}
上述程式碼中,我們建立了一個網路請求方法getData,在方法裡,我們使用URLSession建立網路請求,聲明瞭常量session來使用URLSession API,然後載入的目標地址為宣告的JsonURL,並執行下載資料,當下載成功後,將按照Model資料模型格式的陣列載入到models數組裡,若載入失敗則列印錯誤資訊。
然後我們可以在初始化時呼叫getData獲得資料方法來載入資料,如下程式碼所示:
init(){
getData()
}
由於使用JSONDecoder編碼器,因此Model資料模型還需要設定遵循可編碼性 Codable 協議,才能避免報錯。又因為id在JSON檔案中不存在,因此需要告訴編譯器使用某些CodingKeys,不包括id。如下程式碼所示:
enum CodingKeys : String, CodingKey {
case platformIcon, title, platformName, indexURL
}
上述程式碼中,我們使用列舉類CodingKeys,用來指定Model資料模型中應該接收哪些資料,用於排除請求JSON時缺少ID的問題。另外CodingKey也可以作為關鍵字替換的方法,當實際開發過程中後端與前端定義的欄位名稱不一樣時,也可是使用該方法進行欄位對照對映,這點後面有時間會講到。
ViewModel模型檢視建立完成後,我們來到ContentView檢視,要使用ViewModel模型檢視連結Model和View,我們需要使用新增一個狀態變數,如下程式碼所示:
@StateObject var viewModel = ViewModel()
宣告狀態變數viewModel作用是初始化ViewModel並交由SwiftUI進行管理儲存,這樣我們就可以在View檢視中使用ViewModel模式檢視中的所有方法和變數。
緊接著,我們將原來在List使用的用@State宣告的models陣列替換成viewModel中的陣列models,如下圖所示:
如此,通過URLSession API,我們從網路請求了JSON檔案資料,並把它解析到了LIst中並展示出來了。如下圖所示:
方法優化:優化“新增身份卡”方法
接下來我們來優化新增身份卡的方法,在ViewModel模型檢視中,我們使用@Published聲明瞭資料模型陣列models,並在ContentView頁面中替換了使用@State宣告的models陣列。
因此我們可以將所有網路請求、新增、編輯、刪除的方法都放在ViewModel模型視圖裡,然後在所有頁面建立連結,新增方法如下程式碼所示:
// 建立身份卡
func addCard(newItem: Model) {
models.append(newItem)
}
上述程式碼中,我們建立了一個方法addCard,通過傳入符合Model資料模型格式的常量newItem中,然後將newItem新增到陣列models中,完成新增資料的動作。
接下來回到 NewView中,我們引用ViewModel檢視模型,並替換原來使用@Binding雙向繫結宣告的陣列models,如下程式碼所示:
var viewModel:ViewModel
這時候可能會報錯,沒有關係,這是因為原來@Binding雙向繫結宣告的陣列models建立的關係被破壞掉了,而為什麼不像ContentView那樣使用@StateObject var viewModel = ViewModel()宣告,這是因為在新增頁面,新增的資料要載入到ContentView的List列表中,進行資料之間的傳遞。
新增身份卡的方法需要替換原有的models,換成viewModel檢視模型中的addCard方法,如下程式碼所示:
self.viewModel.addCard(newItem: newItem)
並且NewView頁面預覽時,需要賦予變數viewModel值,如下程式碼所示:
NewView(viewModel: ViewModel())
上述程式碼中,我們使用ViewModel檢視模型代替純Model資料模型的陣列,並將原來的新增身份卡方法替換為ViewModel建立好的addCard方法,為了預覽當前NewView頁面,還需要給NewView宣告的viewModel變數賦予預設值ViewModel()。
在NewView頁面調整後,由於之前我們還在引用NewView檢視的相關頁面進行了繫結,這時候要回到ContentView檢視中,解除之前的繫結,如下圖所示:
NewView(viewModel: viewModel)
如此,我們便實現了使用Model-View-ViewModel架構模式調整原有專案程式碼,並實現引用ViewModel檢視模型中的方法來建立檢視,做到將頁面和資料分隔開,使得程式碼進一步精煉。
方法新增:增加“刪除身份卡”的方法
調整完“新增身份卡”方法後,我們來補充“刪除身份卡”方法。刪除身份卡的方法和新增身份卡方法一樣,我們可以在ViewModel檢視模型中建立,如下程式碼所示:
// 刪除身份卡片
func deleteItem(itemId: UUID) {
models.removeAll(where: {$0.id == itemId})
}
上述程式碼中,我們建立了一個刪除身份卡片的方法deleteItem,傳入身份卡片資料的UUID,作為索引找到對應的身份卡片,然後呼叫removeAll方法,刪除models陣列中對應UUID對傳入的UUID的資料,實現刪除資料的操作。
回到ContentView頁面,我們建立一個簡單的刪除身份卡的互動,使用contextMenu上下文選單按鈕搭建刪除互動,如下程式碼所示:
// 卡片檢視
CardView(platformIcon: item.platformIcon, title: item.title, platformName: item.platformName, indexURL: item.indexURL)
// 長按喚起刪除
.contextMenu {
Button(action: {
self.viewModel.deleteItem(itemId: item.id)
}, label: {
Text("刪除")
})
}
上述程式碼中,我們給CardView卡片檢視添加了一個上下文選單的互動操作,當點選CardView卡片時,喚起上下文選單,點選選單按鈕呼叫viewModel檢視模型的deleteItem刪除方法,指定刪除的卡片id為點選卡片的UUID。
我們長按點選卡片預覽下效果,如下圖所示:
上面的方法是使用contextMenu上下文選單實現身份卡片的方法,比較簡單。
專案預覽
完成後,我們在模擬器中預覽下效果,如下圖所示:
專案小結
在本章中,我們學習了Model-View-ViewModel模型-檢視-模型檢視架構模式進行專案的開發,將使用URLSession API實現網路請求,將JSON資料檔案從雲端請求到本地渲染,其中對於JSON檔案缺少UUID的處理至關重要。
功能方法方面,我們在ViewModel檢視模型中建立了addCard新增身份卡方法替換了原有在View檢視中實現的操作邏輯,進一步地,我們建立了deleteItem刪除身份卡方法,通過識別當前卡片的UUID,指定卡片進行刪除操作。
自此,Linkworld專案的功能越來越完善了,但還不夠好。接下來的章節,我們介紹另一種刪除資料項的互動,以及編輯頁面、排序等功能的實現,請保持期待吧~
版權宣告
本文為稀土掘金技術社群首發簽約文章,14天內禁止轉載,14天后未獲授權禁止轉載,侵權必究!
- 實戰教程·元宇宙來了,準備好你的電子名片了嗎?(一)
- 實戰教程·元宇宙來了,準備好你的電子名片了嗎?(八)
- 實戰教程·什麼年代了還在敲傳統木魚?(二)
- 實戰教程·元宇宙來了,準備好你的電子名片了嗎?(七)
- 實戰教程·元宇宙來了,準備好你的電子名片了嗎?(六)
- 實戰教程·元宇宙來了,準備好你的電子名片了嗎?(五)
- 實戰教程·元宇宙來了,準備好你的電子名片了嗎?(四)
- 實戰教程·元宇宙來了,準備好你的電子名片了嗎?(三)
- 實戰教程·元宇宙來了,準備好你的電子名片了嗎?(二)
- 實戰教程·什麼年代了還在敲傳統木魚?(一)
- 技術下午茶:產品經理是如何工作的?如何才算一份好的需求文件?如何設計一個簡單的列表,它應該具備哪些基本功能?
- 釋出&選擇釋出,使用SwiftUI搭建一個新建釋出彈窗(上)
- 釋出&選擇釋出,使用SwiftUI搭建一個新建釋出彈窗(下)
- 使用SwiftUI搭建一個風箏搖擺動畫,實現放風箏的夢想~
- SwiftUI100天:使用SwiftUI搭建一個計時器App
- 實戰程式設計·使用SwiftUI從0到1完成一款iOS筆記App(三)
- 初識MVVM·關於啟動頁、引導頁、登入頁的設計細節和互動邏輯
- 誰說程式設計師不懂浪漫,教你使用SwiftUI搭建一個電子相簿送給她吧~
- 實戰程式設計·刻在男人DNA裡的浪漫,空氣投籃(二)
- 實戰程式設計·使用SwiftUI從0到1完成一款iOS筆記App(四)