如何使用 Combine 框架和 SwiftUI 发布网络请求的数据
Posted
技术标签:
【中文标题】如何使用 Combine 框架和 SwiftUI 发布网络请求的数据【英文标题】:how to publish the data of a network request using Combine framework and SwiftUI 【发布时间】:2019-10-30 12:05:05 【问题描述】:我正在使用 swiftUI 和 Combine 框架以及 MVVM 开发一个 ios 应用程序。 我想在一个名为 LoginService 的单独类中处理登录 API 请求,该类在 LoginViewModel 中使用。 现在我想知道我应该如何发布和观察视图和视图模型之间的属性。 我的意思是 ViewModel 是一个 ObservableObject 并且正在 View 中被观察,但是由于我在 Service 类中处理网络请求,LoginService 应该如何通知 LoginViewModel 和 LoginView 接收到数据并且应该更新 View?
import Foundation
import Combine
class LoginViewModel: ObservableObject
@Published var user = UserModel()
@Published var LoginStatus: Bool = false
@Published var LoginMessage: String = ""
var service = LoginService()
func Login(With email: String, And password: String) -> Bool
service.validateLogin(email: email, password: password)
return false
这是 LoginViewModel 的代码。 当从服务器接收到数据通知视图时,LoginService 应该如何更改 LoginStatus、LoginMessage 和 user 的值? 我这么说是因为据我所知,您只能在 View(SwiftUI) 中观察 ObservableObjects。
【问题讨论】:
【参考方案1】:好的,我以你的为例,我会做以下事情:
我假设您的服务返回 true
或 false
import Foundation
import Combine
class LoginViewModel: ObservableObject
@Published var LoginStatus: Bool = false
@Published var LoginMessage: String = ""
var service = LoginService()
func Login(_ email: String, _ password: String) -> Bool
self.LoginStatus = service.validateLogin(email: email, password: password)
return self.LoginStatus
在你看来:
import SwiftUI
struct ContentView : View
@ObservedObject var model = LoginViewModel()
var body: some View
VStack
Button(action:
_ = self.model.Login("TestUser", "TestPassword")
, label:
Text("Login")
)
Text(self.model.LoginStatus ? "Logged In" : "Not Logged in")
应该是这样的。
我删除了UserModel
,因为你不应该嵌套模型。
我希望这会有所帮助。
编辑 1:
要自动验证某些内容,您可以在视图上使用 onApear()
或者使用olnrecieve()
监听更改以更新 UI 或状态
import SwiftUI
struct ContentView : View
@ObservedObject var model = LoginViewModel()
var body: some View
VStack
Button(action:
_ = self.model.Login("TestUser", "TestPassword")
, label:
Text("Login")
)
Text(self.model.LoginStatus ? "Logged In" : "Not Logged in")
.onAppear
// call a function that gets something from your server
// and modifies your state
self.model.validate()
.onReceive(self.model.$LoginMessage, perform: message in
// here you can update your state or your ui
// according the LoginMessage... this gets called
// whenever LoginMessage changes in your model
)
【讨论】:
感谢您的回复,但我的问题仍未得到解答。现在我从服务类中的 API 获取数据,我应该如何在视图中访问它们?假设我的 API 返回一个令牌和一个 ID,我想在 View 中显示 ID。 当您更改模型中的@Published
变量时,它会自动更新所有使用它们的视图...我展示了在模型中更改的视图中使用布尔值。通常在处理网络时,您需要在 DispatchQueue.main.async
块中更新 @Published
变量
要自动触发验证,您可以使用onAppear()
我将编辑答案【参考方案2】:
您已建立单向绑定,即;模型 -> 视图
现在,无论您的服务如何更新模型,无论何时模型更改,查看更新都无关紧要。
您的服务可以通过多种方式更新模型。
常用URLSession,在回调中照常更新LoginStatus和LoginMessage。
通过联合发布者,例如; URLSessionDataTaskPublisher,并在其接收器闭包中进行更新。
【讨论】:
以上是关于如何使用 Combine 框架和 SwiftUI 发布网络请求的数据的主要内容,如果未能解决你的问题,请参考以下文章
使用 Combine 和 SwiftUI 在 Realm 中观察收集结果
SwiftUI + Combine:如何将数据分配给带有动画的模型
使用 SwiftUI、Combine 和 Firebase,我如何在将用户的帐户链接到电子邮件/密码之前验证用户是不是已匿名登录?
SwiftUI ObjectBinding 不会使用 combine 接收来自可绑定对象的 didchange 更新