问题描述
protocol Identifiable {
var id: String { get }
}
struct ModelA: Identifiable {
var id: String
}
struct ModelB: Identifiable {
var id: String
}
protocol ViewModelable {
associatedtype model: Identifiable
}
struct ViewModelA: ViewModelable {
typealias model = ModelA
}
class ViewA: UIView {
var viewModel: ViewModelA
}
struct ViewModelB: ViewModelable {
typealias model = ModelB
}
class ViewB: UIView {
var viewModel: ViewModelB
}
class CustomListView: UIView {
var viewModels<T: ViewModelable>: [T]?
var viewmodels:[ViewModelable]
}
我需要对我的视图模型将持有的模型强制执行规则。但是 View1 中的语法会引发编译错误。 (协议 'ViewModelable' 只能用作通用约束,因为它具有 Self 或相关的类型要求)。那么我还有其他方法可以强制执行此操作吗?
我的用例:
自定义列表视图是一种容器视图,它将具有一个表视图并呈现视图(viewmodelA 和 viewmodelB)
解决方法
您可以在类型定义期间强制执行。
class View1<T: ViewModelable>: UIView {
var viewmodels: [T] = []
}
许多标准 API 都这样做。
Array<Element>
Dictionary<Key: Hashable etc.
更新
要通过返回 id
的所有这些协议访问您的财产,您可以这样做。
protocol ViewModelable {
associatedtype Model: Identifiable
var model: Model { get }
}
struct ViewModelA: ViewModelable {
typealias Model = ModelA
var model: Model
}
struct ViewModelB: ViewModelable {
typealias Model = ModelB
var model: Model
}
class View1<T: ViewModelable>: UIView {
var viewModels: [T] = []
func doSomething() {
let firstModelID = viewModels.first?.model.id
}
}
更新 2
自定义列表视图是一种容器视图,它将具有一个表视图并呈现视图(viewmodelA 和 viewmodelB)
class CustomListView1<A: ViewModelable,B: ViewModelable>: UIView {
var viewModelAs: [A] = []
var viewModelBs: [B] = []
}
/// You can go one step further as well
class CustomListView2<A: ViewModelable,B: ViewModelable>: UIView
where A.Model == ModelA,B.Model == ModelB {
var viewModelAs: [A] = []
var viewModelBs: [B] = []
}
更新 3
有 5 个以上的视图模型,并且所有视图模型都呈现在一个 tableview 中,因此无法将其保存在单独的数组中。
class View2: UIView {
enum ViewModel {
case viewModelA(ViewModelA)
case viewModelB(ViewModelB)
// Add as many variants as you want
var model: Identifiable {
switch self {
case .viewModelA(let vma): return vma.model
case .viewModelB(let vmb): return vmb.model
}
}
}
var viewModels: [ViewModel] = []
func doSomething() {
let firstModelID = viewModels.first?.model.id
}
}