Swiftui 有没有一种方法可以像下面这样将视图与视图模型解耦?

Swiftui 有没有一种方法可以像下面这样将视图与视图模型解耦?,swiftui,combine,Swiftui,Combine,我的目标是两件事: 1.使视图依赖于视图模型协议而不是具体的类。 2.子视图从环境中获取视图模型,而不是通过视图层次结构传递它 我已经提到了我的目标,所以如果有完全不同的方法来实现它们,我愿意接受建议。 下面是我们尝试过但失败了的东西,当然也会引起奇怪的错误: struct ContentView: View { var body: some View { NavigationView { MyView() } } } s

我的目标是两件事: 1.使视图依赖于视图模型协议而不是具体的类。 2.子视图从环境中获取视图模型,而不是通过视图层次结构传递它 我已经提到了我的目标,所以如果有完全不同的方法来实现它们,我愿意接受建议。 下面是我们尝试过但失败了的东西,当然也会引起奇怪的错误:

struct ContentView: View {
    var body: some View {
        NavigationView {
            MyView()
        }
    }
}

struct MyView: View {
    @EnvironmentObject var viewModel: some ViewModelProtocol

    var body: some View {
        HStack {
            TextField("Enter something...", text:$viewModel.text)
            Text(viewModel.greetings)
        }
    }
}

//MARK:- View Model
protocol ViewModelProtocol: ObservableObject {
    var greetings: String { get }
    var text: String { get set }
}

class ConcreteViewModel: ViewModelProtocol {
    var greetings: String { "Hello everyone..!" }
    @Published var text = ""
}

//MARK:- Usage
let parent = ContentView().environmentObject(ConcreteViewModel())


是的,有,但不太漂亮

您遇到了一些问题,因为编译器无法理解如何推断某个协议应该是什么类型

some
在声明视图时起作用的原因是,它是从您提供给它的任何内容的类型推断出来的

如果使视图结构采用通用的viewmodel类型,则可以将其设置并编译

struct MyView<ViewModel: ViewModelProtocol>: View {
    @EnvironmentObject var viewModel: ViewModel

    var body: some View {
        Text(viewModel.greetings)
    }
}
struct MyView:View{
@EnvironmentObject变量viewModel:viewModel
var body:一些观点{
文本(viewModel.greetings)
}
}
这里最糟糕的是,无论何时使用此视图,都必须声明viewmodel的类型,如下所示:

let test: MyView<ConcreteViewModel> = MyView()
let test:MyView=MyView()

是的,有,但不太漂亮

您遇到了一些问题,因为编译器无法理解如何推断某个协议应该是什么类型

some
在声明视图时起作用的原因是,它是从您提供给它的任何内容的类型推断出来的

如果使视图结构采用通用的viewmodel类型,则可以将其设置并编译

struct MyView<ViewModel: ViewModelProtocol>: View {
    @EnvironmentObject var viewModel: ViewModel

    var body: some View {
        Text(viewModel.greetings)
    }
}
struct MyView:View{
@EnvironmentObject变量viewModel:viewModel
var body:一些观点{
文本(viewModel.greetings)
}
}
这里最糟糕的是,无论何时使用此视图,都必须声明viewmodel的类型,如下所示:

let test: MyView<ConcreteViewModel> = MyView()
let test:MyView=MyView()

完全正确。我不想让内容视图知道任何关于“MyView”视图模型具体类型的信息。事实上,我试图逃避一般的解决方案,却找不到一个合适的解决方案。所以我决定发布一个问题。我不想让内容视图知道任何关于“MyView”视图模型具体类型的信息。事实上,我试图逃避一般的解决方案,却找不到一个合适的解决方案。所以我决定发布一个问题