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,并且仅当特定属性更改时,它才允许我们更新视图


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM