SwiftUI - MVVM之ViewModel
Posted liuxiaokun
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SwiftUI - MVVM之ViewModel相关的知识,希望对你有一定的参考价值。
SwiftUI - MVVM之ViewModel
什么是ViewModal
ViewModal是View和数据的中间层。ViewModel是视图和数据之间的一层。 ViewModel通常使用service objects来获取数据,对其进行格式化后向View提供格式化的数据。
苹果什么时候开始推动MVVM
当苹果将ObservableObject协议移至Combine框架时,苹果公司开始推广MVVM模式。让我们看一下ObservableObject协议,以了解发生了什么。
/// A type of object with a publisher that emits before the object has changed.
public protocol ObservableObject : AnyObject {
/// The type of publisher that emits before the object has changed.
associatedtype ObjectWillChangePublisher : Publisher = ObservableObjectPublisher where Self.ObjectWillChangePublisher.Failure == Never
/// A publisher that emits before the object has changed.
var objectWillChange: Self.ObjectWillChangePublisher { get }
}
ObservableObject协议具有唯一的要求,即在对象更改之前发出的发布者。让我们编写第一个符合ObservableObject协议的ViewModel。
final class PostsViewModel: ObservableObject {
let objectWillChange = PassthroughSubject<Void, Never>()
private (set) var posts: [Post] = []
func fetch() {
// fetch posts
objectWillChange.send()
// assign new data to the posts variable
}
}
在这里,我们有ViewModel来获取帖子,将它们存储在变量中,并通过objectWillChange发布者发出通知。让我们看一下使用此ViewModel的示例ViewController。
final class PostsViewController: UIViewController {
let viewModel: PostsViewModel
override func viewDidLoad() {
super.viewDidLoad()
bindViewModel()
viewModel.fetch()
}
private func bindViewModel() {
viewModel.objectWillChange.sink { [weak self] in
guard let self = self else {
return
}
self.renderPosts(self.viewModel.posts)
}
}
}
如您在上面的示例中看到的,我们有PostsViewController,它开始观察ViewModel中的更改,然后要求ViewModel提取数据。一旦ViewModel提取数据,它就会发出,并且ViewController调用renderPosts函数,该函数显示下载的帖子。
Published property wrapper
我们可以使用@Published属性包装器进行进一步操作。 @Published属性包装器允许我们将发布者包装任何属性,只要属性更改,发布者就会发出当前值。
final class PostsViewModel: ObservableObject {
@Published private(set) var posts: [Post] = []
func fetch() {
// fetch posts and assign them to `posts` variable
}
}
正如您在上面的示例中看到的那样,我们不需要手动将值发送给objectWillChange发布者,这是Swift编译器合成的所有工作。并且我们可以保持PostsViewController的相同实现。
如前所述,@ Published属性包装器将我们的属性与发布者包装在一起。让我们看看如何在PostsViewController中使用它
final class PostsViewController: UIViewController {
let viewModel: PostsViewModel
override func viewDidLoad() {
super.viewDidLoad()
bindViewModel()
viewModel.fetch()
}
private func bindViewModel() {
viewModel.$posts.sink { [weak self] posts in
self?.renderPosts(posts)
}
}
}
在这里,我们有一个PostsViewController的重构版本。请看一下我们如何更改bindViewModel函数。它现在订阅$ posts,并且仅当特定属性更改时,它才允许我们更新视图
以上是关于SwiftUI - MVVM之ViewModel的主要内容,如果未能解决你的问题,请参考以下文章
SwiftUI MVVM 将变量从 ViewModel 传递到 API 服务
如何在 SwiftUI 中通过 ViewModel 传播模型更改?