为了使我的代码具有可测试性,我试图通过让我的Liskov代换原理视图依赖于协议而不是具体类型来坚持SwiftUI。这使我可以轻松地交换实现,并且可以轻松地构建用于测试的模拟。下面是我要做的事情的一个例子:
protocol DashboardViewModel: ObservableObject {
var orders: [Order] { get }
}我的DashboardViewModel需要将更改传递回它的依赖方,所以我也附加了ObservableObject作为传递的需求。
这似乎是个问题。如果您有关联的类型需求,则无法实现LSP。下面是我从SwiftUI视图类中获得的错误,它依赖于我的视图模型:
struct DashboardView: View {
@ObservedObject var viewModel: DashboardViewModel
}协议'DatastoreProtocol‘只能用作泛型约束,因为它具有自或关联的类型要求
我最终还是这么做了:
protocol DashboardViewModel {
var orders: [Order] { get }
var objectWillChange: AnyPublisher<Void, Never> { get }
}这还要求受抚养人做额外的工作来观察状态更改。这就消除了使用属性包装器的方便性--主要是受抚养人使用@ObservedObject观察状态更改的能力。使用此选项将导致我们编写如下代码:
struct DashboardView: View {
let viewModel: DashboardViewModel
var viewModelSubscriber: AnyCancellable!
// MARK: - Used only to force a re-render of this view
@State private var reload = false
init(viewModel: DashboardViewModel) {
self.viewModel = viewModel
viewModelSubscriber = viewModel.objectWillChange.sink { _ in
self.reload.toggle()
}
}
}这是一种令人讨厌的东西:
@State变量,因为我们不能利用SwiftUI属性包装来观察状态更改。AnyCancellable!变量,以保存视图模型中对objectWillChange的订阅。这是从DashboardViewModel检测状态更改所必需的。@State变量以强制从视图模型检索新数据。我觉得应该有更好的方法来处理这件事。寻求帮助!
发布于 2019-08-20 18:18:54
解决这一问题的一种方法是使视图具有通用性:
protocol DashboardViewModel: ObservableObject {
var orders: [Order] { get }
}
struct DashboardView<Model: DashboardViewModel>: View {
@ObservedObject var viewModel: Model
}https://stackoverflow.com/questions/57579380
复制相似问题