问题描述
我有一个依赖于视图模型的 swiftui 视图,视图模型有一些已发布的属性.我想为视图模型层次结构定义一个协议和默认实现,并使视图依赖于协议而不是具体类?
I have a swiftui view that depends on a view model, the view model has some published properties. I want define a protocol and default implementation for the view model hierarchy, and make the view dependent on the protocol not the concrete class?
我希望能够编写以下内容:
I want to be able to write the following:
protocol ItemViewModel: ObservableObject {
@Published var title: String
func save()
func delete()
}
extension ItemViewModel {
@Published var title = "Some default Title"
func save() {
// some default behaviour
}
func delete() {
// some default behaviour
}
}
struct ItemView: View {
@ObservedObject var viewModel: ItemViewModel
var body: some View {
TextField($viewModel.title, text: "Item Title")
Button("Save") { self.viewModel.save() }
}
}
// What I have now is this:
class AbstractItemViewModel: ObservableObject {
@Published var title = "Some default Title"
func save() {
// some default behaviour
}
func delete() {
// some default behaviour
}
}
class TestItemViewModel: AbstractItemViewModel {
func delete() {
// some custom behaviour
}
}
struct ItemView: View {
@ObservedObject var viewModel: AbstractItemViewModel
var body: some View {
TextField($viewModel.title, text: "Item Title")
Button("Save") { self.viewModel.save() }
}
}
推荐答案
Swift 协议和扩展中不允许使用包装器和存储属性,至少目前是这样.所以我会采用以下混合协议、泛型和类的方法......(所有这些都可以用 Xcode 11.2/iOS 13.2 编译和测试)
Wrappers and stored properties are not allowed in swift protocols and extensions, at least for now. So I would go with the following approach mixing protocols, generics and classes... (all compilable and tested with Xcode 11.2 / iOS 13.2)
// base model protocol
protocol ItemViewModel: ObservableObject {
var title: String { get set }
func save()
func delete()
}
// generic view based on protocol
struct ItemView<Model>: View where Model: ItemViewModel {
@ObservedObject var viewModel: Model
var body: some View {
VStack {
TextField("Item Title", text: $viewModel.title)
Button("Save") { self.viewModel.save() }
}
}
}
// extension with default implementations
extension ItemViewModel {
var title: String {
get { "Some default Title" }
set { }
}
func save() {
// some default behaviour
}
func delete() {
// some default behaviour
}
}
// concrete implementor
class SomeItemModel: ItemViewModel {
@Published var title: String
init(_ title: String) {
self.title = title
}
}
// testing view
struct TestItemView: View {
var body: some View {
ItemView(viewModel: SomeItemModel("test"))
}
}
这篇关于如何将协议定义为@ObservedObject 属性的类型?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!