如何将协议定义为@ObservedObject 属性的类型? [英] How to define a protocol as a type for a @ObservedObject property?

查看:39
本文介绍了如何将协议定义为@ObservedObject 属性的类型?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个依赖于视图模型的 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 属性的类型?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆