zoukankan      html  css  js  c++  java
  • SwiftUI

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

  • 相关阅读:
    万能五笔的广告怎么去掉
    JS版日期格式化和解析工具类,毫秒级
    Toast信息提示:下拉收起(基于jQuery)(app信息提示更新)
    MUI右滑关闭窗口用Webview的drag实现
    mui 列表项左右滑删除功能升级(仿微信左滑 点击删除后出现确认删除)
    修正 Mui 下拉上拉刷新功能
    javascript中new Date()的浏览器兼容性问题
    Mui 下拉刷新,刷新完成功能实现
    mysql 时间类型精确到毫秒、微秒及其处理
    Windows 上如何安装Sqlite
  • 原文地址:https://www.cnblogs.com/liuxiaokun/p/12684399.html
Copyright © 2011-2022 走看看