Skip to content

13.3_当ViewModel数据变化时更新UI组件

在 MVVM 架构中,当 ViewModel 的数据发生变化时,如何高效且优雅地更新 UI 组件是至关重要的。让我们一起探索如何在 iOS 18 中,利用 UIKit 和纯代码实现这一目标!🚀

观察者模式与数据绑定

首先,你需要理解观察者模式。ViewModel 充当被观察者,而 ViewController 中的 UI 组件则是观察者。当 ViewModel 中的数据改变时,它会通知所有订阅的观察者,从而触发 UI 更新。数据绑定是实现这一过程的关键。

  • KVO (Key-Value Observing):这是 Objective-C 时代的经典方法,但在 Swift 中使用起来稍显繁琐。
  • Combine: 这是苹果官方推出的响应式编程框架,非常适合处理异步事件和数据流。
  • 闭包 (Closures):你可以使用闭包作为回调函数,在 ViewModel 数据变化时执行 UI 更新。

使用 Combine 实现 UI 更新

Combine 框架提供了强大的数据流处理能力。你可以使用 Published 属性包装 ViewModel 中的数据,使其成为可观察的属性。在 ViewController 中,使用 sink 方法订阅这些属性的变化,并更新 UI。

swift
class MyViewModel {
    @Published var title: String = "初始标题"
}

class MyViewController: UIViewController {
    let viewModel = MyViewModel()
    var titleLabel: UILabel!
    private var cancellables: Set<AnyCancellable> = []

    override func viewDidLoad() {
        super.viewDidLoad()
        viewModel.$title
            .sink { [weak self] newTitle in
                self?.titleLabel.text = newTitle
            }
            .store(in: &cancellables)
    }
}

使用闭包进行简单的数据绑定

如果你不想引入 Combine 框架,可以使用闭包来实现简单的数据绑定。在 ViewModel 中定义一个闭包属性,并在数据变化时调用它。在 ViewController 中,将 UI 更新代码赋值给这个闭包。

swift
class MyViewModel {
    var title: String = "初始标题" {
        didSet {
            titleDidChange?(title)
        }
    }
    var titleDidChange: ((String) -> Void)?
}

class MyViewController: UIViewController {
    let viewModel = MyViewModel()
    var titleLabel: UILabel!

    override func viewDidLoad() {
        super.viewDidLoad()
        viewModel.titleDidChange = { [weak self] newTitle in
            self?.titleLabel.text = newTitle
        }
    }
}

线程安全与 UI 更新

UI 更新必须在主线程上进行。当 ViewModel 在后台线程更新数据时,你需要确保 UI 更新代码在主线程上执行。你可以使用 DispatchQueue.main.async 来实现这一点。

swift
viewModel.$title
    .sink { [weak self] newTitle in
        DispatchQueue.main.async {
            self?.titleLabel.text = newTitle
        }
    }
    .store(in: &cancellables)

优化 UI 更新性能

频繁的 UI 更新可能会影响性能。你可以使用以下技巧来优化 UI 更新:

  1. Diff 算法: 只更新需要改变的部分,而不是整个 UI 组件。
  2. 节流 (Throttling):限制 UI 更新的频率。
  3. 延迟更新: 在短时间内合并多次数据变化,然后一次性更新 UI。

通过以上方法,你可以确保 ViewModel 的数据变化能够及时、高效地反映在 UI 上,从而提升用户体验。🎉

本站使用 VitePress 制作