嗨,我只是想知道是否可以创建一个通用类,以确认ObservableObject协议,该协议可以被多个ContentView使用。
如果我能做到这一点,那么我将能够使ContentView和Model类完全通用且可重用。
我想要达到的目标的一个例子:
protocol ContentViewModelType: ObservableObject {
var propertyToInitialiseView: [String] { get }
}
struct ContentView: View {
@ObservedObject var viewModel: some ViewModel
var body: some View {
Text("Hello World")
}
}
如果可以的话,任何类都可以实现ContentViewModelType并成为ContentView的模型,从而使其具有通用性和可重用性。例如
class ViewModel: ObservableObject {
var objectWillChange = PassthroughSubject<ViewModel, Never>()
}
但是当我尝试初始化ContentView时,xcode给了我一个类型错误。
我认为引入一些关键字的全部目的是,以便我们可以将协议作为类型用于那些将类型关联为要求的协议,因此这应该可行。但这会出错。
如果任何人都可以分享有关此问题的任何参考或知识,或者可能对此有解决方案,那就太好了。
谢谢。
答案 0 :(得分:2)
这不是some
的用途。 some
创建一个不透明的返回类型,而不是一个存在(“ any”)类型。 See the docs for more detail.另请参见What is the `some` keyword in SwiftUI?
some
类型必须是在编译时已知的单个类型。只是呼叫者不知道。您想要做的是传递一个存在的存在,这是 runtime 已知的类型。在Swift 5.1中,关于存在性的一切都没有改变。如果这是您想要的,您仍然需要将其包装在AnyContentViewModel
中。 (我需要考虑一下这是否是一个好主意。)
但是您编写的代码也无法满足您的描述。您实际上并没有在任何地方使用ContentViewModelType
。您是说some ContentViewModelType
吗?那仍然行不通,但这似乎是您的意思。
答案 1 :(得分:1)
试图理解您的问题,但我不确定我是否理解意图...但是要创建一个采用通用视图模型的视图(基于之前的协议),您将需要以下代码: / p>
protocol ViewModelWithProperties: ObservableObject {
var properties: [String] { get }
}
struct SomeView<T>: View where T: ViewModelWithProperties {
// this can also be written as
// struct SomeView<T: ViewModelWithProperties>: View {
@ObservedObject var item: T
var body: some View {
VStack {
ForEach(item.properties, id: \.self) {
Text($0)
}
}
}
}
要使用此实例,您需要:
struct ContentView: View {
var body: some View {
SomeView(item: MyViewModel())
}
}
如其他答案之一所述,some
用于不透明类型,它不会使您的代码通用。
答案 2 :(得分:-1)
如果我对您的理解正确,则可以执行以下操作:
您可以具有一个ObservableObject类,如下所示:
import Foundation
class SampleTimer: ObservableObject {
@Published var timerVar: Int = 0
init(){
Timer.scheduledTimer(withTimeInterval: 1, repeats: true){
timer in
DispatchQueue.main.async {
self.timerVar += 1
}
}
}
}
ContentView:
import SwiftUI
struct ContentView: View {
@ObservedObject var sampleTimer = SampleTimer()
var body: some View {
NavigationView {
VStack {
Text("\(sampleTimer.timerVar)")
NavigationLink(destination: SecondView(sampleTimer: sampleTimer) ){
Text("Go to second view")
}
}
}
}
}
和类似的SecondView:
import SwiftUI
struct SecondView: View {
@ObservedObject var sampleTimer : SampleTimer
var body: some View {
VStack {
Text("\(sampleTimer.timerVar)")
}
}
}
我要概述的重要一点是,如果您有一个像我一样的计时器,并且在init()
函数中对其进行了初始化,然后在{{1}中创建了SampleTimer()
的新实例}(即SecondView
而不是我拥有的)而不是将同一实例从@ObservedObject var sampleTimer = SampleTimer()
传递到ContentView()
,您将拥有SecondView()
的两个不同实例SampleTimer
和ContentView