
让我们考虑一个引用视图模型的视图的简单示例,而不用考虑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} 使用上述代码,您将遇到“类型”可能不会将其自身参考为所提供链接中所讨论的要求.
然后(天真的,因为我),我以为我可以解决这个做:
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: viewmodellet v = VIEw(viewmodel: vm) // Type: VIEw<viewmodel>vm.delegate = v 主要思想是介绍一个中介对象或一个委托对象来处理视图和视图模型之间的通信.对这个委托的引用类型为Any,以破坏循环协议约束.我看到的唯一的缺点是代理需要从外部设置,从创建对象的位置设置,并且不能在VIEw实现中设置.如果尝试这样做,错误无法分配VIEw< VM>类型的值输入 _?会出现.
然而,通过这种方法,我们可以得到正确的类型,而无需做很多专业化.当然,可以添加更多的协议来获得更多的抽象,但同样的解决方案将会适用.
由于某些原因/语言缺陷,您必须在VIEw.foo中分配委托时使用显式转换:viewmodel.delegate = self as? VM.D但是为什么要使用结构体而不是类?我想你想要类,特别是你不希望所有的VIEw / viewmodel变量在修改时复制 – 而不是被引用 – 当你做类似的事情
var vm = viewmodel() // Type: viewmodellet v = VIEw(viewmodel: vm) // Type: VIEw<viewmodel> vm.delegate = v
特别
func foo() { viewmodel.delegate = self} 不起作用,除非你声明VIEw.foo是变异的,这将需要几乎所有的东西(包括VIEwDelegate.foo和viewmodel.bar)进行突变,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: viewmodellet v = VIEw(viewmodel: vm) // Type: VIEw<viewmodel>v.foo() // VIEw<viewmodel>vm.delegate // VIEw<viewmodel> 还有一件事:为什么不在视图类的初始化器中分配委托,如:
// initializer needed,because we are no struct any moreinit(viewmodel vm:VM) { self.viewmodel = vm self.viewmodel.delegate = self as? VM.D} 然后,您可以跳过v.foo()的调用,以设置委托.
总结以上是内存溢出为你收集整理的解决Swift 3中缺少递归协议约束的问题全部内容,希望文章能够帮你解决解决Swift 3中缺少递归协议约束的问题所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)