SwiftUI蘋果提供的開箱即用MVVM之ViewModel

SwiftUI蘋果提供的開箱即用MVVM之ViewModel

什麼是ViewModal

ViewModal是View和數據的中間層。ViewModel是視圖和數據之間的一層。 ViewModel一般使用service objects來獲取數據,對其進行格式化後向View提供格式化的數據。swift

蘋果何時開始推進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。app

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函數,該函數顯示下載的帖子。ide

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中使用它post

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,而且僅當特定屬性更改時,它才容許咱們更新視圖。只要您的ViewModel有愈來愈多的會影響視圖的字段,您就會當即看到好處。fetch

總結

咱們可使用RxSwift,ReactiveSwift或任何其餘反應式框架(如Bond)輕鬆實現相同的邏輯。但我以爲MVVM將成爲架構iOS應用程序的默認選擇。至少到如今,當Apple爲咱們提供了開箱即用的全部必要工具時。ui

文章來源

https://swiftwithmajid.com/2020/02/05/building-viewmodels-with-combine-framework/

更多SwiftUI教程和代碼關注專欄

QQ:3365059189
SwiftUI技術交流QQ羣:518696470

https://www.jianshu.com/c/7b3...

相關文章
相關標籤/搜索