SwiftUI中Presenter的viewModel用@Published还是@ObservedObject?为什么
结论
你给出的两种写法在当前普通Presenter类的场景下均不正确,两个属性包装器的适用场景都和当前使用位置不匹配。
各写法错误原因
关于
@ObservedObject private(set) var viewModel: ContentViewModel@ObservedObject是SwiftUI框架专门为符合View协议的结构体设计的属性包装器,作用是让视图层可以监听ObservableObject对象的变更,自动触发视图重绘。它只能在View内部使用,放在普通业务类中完全不会生效,也没有对应作用,编译器还会抛出无效使用的警告。关于
@Published private(set) var viewModel: ContentViewModel@Published是专门给遵守ObservableObject协议的类的内部属性使用的属性包装器。它的作用是当被修饰的属性值发生变化时,自动调用所属类的objectWillChange发送变更通知。如果你的Presenter本身没有遵守ObservableObject协议,添加@Published修饰不会产生任何预期效果。
正确实现方案
如果你需要在Presenter类中持有并监听ContentViewModel的变更,直接声明属性手动订阅变更即可,示例如下:
import Combine class Presenter { private(set) var viewModel: ContentViewModel // 存储订阅令牌 private var cancellables = Set<AnyCancellable>() init(viewModel: ContentViewModel) { self.viewModel = viewModel // 手动订阅viewModel的变更事件 viewModel.objectWillChange .sink(receiveValue: { [weak self] _ in // 此处处理viewModel变化后的业务逻辑 }) .store(in: &cancellables) } }
如果你的Presenter本身是需要给SwiftUI视图监听的业务层对象,那让Presenter遵守ObservableObject协议即可,此时如果要把viewModel的变更同步给外部视图,也可以在订阅时手动发送Presenter自己的变更通知:
import Combine class Presenter: ObservableObject { private(set) var viewModel: ContentViewModel private var cancellables = Set<AnyCancellable>() init(viewModel: ContentViewModel) { self.viewModel = viewModel // 把viewModel的变更转发为Presenter自身的变更,供外部View监听 viewModel.objectWillChange .sink(receiveValue: { [weak self] _ in self?.objectWillChange.send() }) .store(in: &cancellables) } }
内容的提问来源于stack exchange,提问作者BollMose

