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