前提回忆

在前几个章节中,咱们已经完结了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": "/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 = "https://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天后未获授权制止转载,侵权必究!