让我们考虑引用视图模型的视图的简单示例,反之,不要考虑ref / value类型以及任何保留周期:
protocol ViewModelType {
associatedtype V: ViewType
var view: V { get }
}
struct ViewModel<V: ViewType>: ViewModelType {
var view: V
}
protocol ViewType {
associatedtype VM: ViewModelType
var viewModel: VM { get }
}
struct View<VM: ViewModelType>: ViewType {
var viewModel: VM
}
使用上面的代码,您将遇到提供的链接中讨论的Type may not reference itself as a requirement
。
然后(我很天真),我以为我可以通过这样做来解决这个问题:
protocol _ViewModelType {}
protocol ViewModelType: _ViewModelType {
associatedtype V: _ViewType
var view: V { get }
}
struct ViewModel<V: ViewType>: ViewModelType {
var view: V
}
protocol _ViewType {}
protocol ViewType: _ViewType {
associatedtype VM: _ViewModelType
var viewModel: VM { get }
}
struct View<VM: ViewModelType>: ViewType {
var viewModel: VM
}
这会导致错误,但它基本上只是推迟了问题。因为现在当我们想构建我们的具体类型时,我们最终会进入一个永无止境的专业化循环:
let vm = ViewModel<View<ViewModel<View...>>>()
我认为这是我想在协议中加入的一个基本约束,但目前我没有看到如何做到这一点。在Swift更新之前,是否可以解决这个问题?或者我需要开始引入不太严格的协议,直到在Swift中实现它?
2016年8月19日更新
经过多方努力找出解决这个问题的最佳方法后,我相信我找到了一个可以接受的解决方案,只需要很少的妥协:
protocol ViewModelType {
associatedtype D: Any // Compromise to avoid the circular protocol constraints.
var delegate: D? { get set }
}
protocol ViewType {
associatedtype VM: ViewModelType
var viewModel: VM { get }
}
protocol ViewDelegate {
func foo()
}
struct ViewModel: ViewModelType {
typealias D = ViewDelegate
var delegate: D?
func bar() {
delegate?.foo() // Access to delegate methods
}
}
struct View<VM: ViewModelType>: ViewType, ViewDelegate {
var viewModel: VM
func foo() {
// Preferred, but not possible: viewModel.delegate = self
}
}
var vm = ViewModel() // Type: ViewModel
let v = View(viewModel: vm) // Type: View<ViewModel>
vm.delegate = v
主要思想是,引入中介对象或委托对象,以处理视图和视图模型之间的通信。对该委托的引用是Any
类型,以打破循环协议约束。我认为唯一的缺点是委托需要“从外部”设置,从中创建对象,并且不能在View
实现中设置。如果尝试执行此操作,则会显示错误Cannot assign value of type View<VM> to type _?
。
但是,通过这种方法,我们可以获得正确的类型,而无需进行大量的专业化。当然,可以添加更多协议以获得更多抽象,但同样的解决方案也适用。
答案 0 :(得分:1)
由于某些原因/语言缺陷,您必须在iss: www.amazon.com
aud: App Id
sub: Sub from the LWA token.
中分配代理时使用显式转换:View.foo
但为什么你要使用结构而不是类?我认为你想要课程,尤其是你不希望所有那些View / ViewModel变量在修改时被复制 - 而不是被引用 - 当你做类似的事情时
viewModel.delegate = self as? VM.D
特别是
var vm = ViewModel() // Type: ViewModel
let v = View(viewModel: vm) // Type: View<ViewModel>
vm.delegate = v
除非您将func foo() {
viewModel.delegate = self
}
声明为View.foo
,否则无法工作,这将需要制作几乎所有内容(包括mutating
和ViewDelegate.foo
){{ 1}}和ViewModel.bar
不能再是常数了。
虽然下面的解决方案也适用于结构体,但我只是改变了类:
mutating
还有一件事:为什么不在视图类的初始化程序中分配委托,例如:
v = View(viewModel: vm)
然后,您可以跳过调用protocol ViewModelType {
associatedtype D: Any // Compromise to avoid the circular protocol constraints.
var delegate: D? { get set }
}
protocol ViewType {
associatedtype VM: ViewModelType
var viewModel: VM { get }
}
protocol ViewDelegate {
func foo()
}
class ViewModel: ViewModelType {
typealias D = ViewDelegate
var delegate: D?
func bar() {
delegate?.foo() // Access to delegate methods
}
}
class View<VM: ViewModelType>: ViewType, ViewDelegate {
var viewModel: VM
// initializer needed, because we are no struct any more
init(viewModel vm:VM) {
self.viewModel = vm
}
func foo() {
viewModel.delegate = self as? VM.D
}
}
var vm = ViewModel() // Type: ViewModel
let v = View(viewModel: vm) // Type: View<ViewModel>
v.foo() // View<ViewModel>
vm.delegate // View<ViewModel>
以设置代理。