我试图在Swift文件中定义一些协议,但我注意到如果协议有交叉引用,XCode就会变得越来越糟糕,并且无法使用该项目。使用的协议的示例可能是下面使用的协议:
protocol VIPERPresenterProtocol
{
var view: VIPERViewProtocol? { get set }
var interactor: VIPERInteractorInputProtocol? { get set }
var wireFrame: VIPERWireFrame? { get set }
// /* Add your extra communication methods here */
// /* Presenter -> ViewController */
}
protocol VIPERViewProtocol
{
var presenter: VIPERPresenterProtocol? { get set }
}
VIPERPresenterProtocol引用了VIPERViewProtocol,最后一个引用了VIPERPresenterProtocol。
这是在Objective-C中有效的,但Swift并不喜欢。我的问题是,如果这可能是Swift语言的一个错误,或者我是否应该以任何其他方式实现这一点,这是Apple在Swift中不支持的东西。
答案 0 :(得分:1)
您的问题有以下形式:
protocol A
{
var b: B? { get set }
}
protocol B
{
var a: A? { get set }
}
但是,虽然两个协议声明都是编译的,但任何实现它们的尝试都不会:
protocol A {
var b: B? { get set }
}
protocol B {
var a: A? { get set }
}
// on their own, the two protocol declerations compile
class Ca: A { // Does not compile: --> Segmentation fault 11
var b: B?
}
如果我们打破这个循环,就不会发生这种情况:
protocol A {}
protocol B {
var a: A? { get set }
}
class Ca: A {}
class Cb: B {
var a: A?
}
let cb = Cb() // --> {nil}
cb.a = Ca() // --> {{Ca}}
cb.a // --> {Ca}
或者,如果我们根据具体类型定义两个协议:
protocol A {
var b: Cb? { get set }
}
protocol B {
var a: Ca? { get set }
}
class Ca: A {
var b: Cb?
let i = "A"
}
class Cb: B {
var a: Ca?
let i = "B"
}
let cb = Cb() // --> {nil "B"}
cb.a = Ca() // --> {{{...}} "B"}
cb.a // --> {{nil "A"}}
cb.a!.b = Cb() // --> {{{...} "A"}}
我的印象是类型检查器还不能处理递归类型声明。不管它是否曾经,在这一点上甚至对苹果来说可能是一个悬而未决的问题,但是,由于明确意图促进功能习语,这至少是一种可能性。
之前我已回答similar question,因为我最终在@newacct的帮助下意识到,并不完全相同。
我刚刚升级到 Xcode 6.1 GM Seed ,情况发生了变化!以下片段现在编译并且似乎运行正常!
protocol A {
var b: B? { get set }
}
protocol B {
var a: A? { get set }
}
class Ca: A {
var b: B?
}
class Cb: B {
var a: A?
}
let a = Ca() // --> {nil}
let b = Cb() // --> {nil}
a.b = b // --> {{{...}}}
b.a = a // --> {{{...}}}
(但是,此改进不会扩展到recursively defined associated types。)
答案 1 :(得分:0)
我试图为VIPER构建类似的东西,我遇到了同样的问题。
我在milos的好答案中添加了一些内容:即使使用相关类型,使用一些支持协议,我也成功地打破了循环。
protocol _VIPERViewProtocol {
}
protocol VIPERViewProtocol : _VIPERViewProtocol {
typealias P:_VIPERPresenterProtocol
var presenter: P! {get set}
}
protocol _VIPERPresenterProtocol {
}
protocol VIPERPresenterProtocol : _VIPERPresenterProtocol {
typealias W:_VIPERViewProtocol
var view: W! {get set}
}
这样做的好处是让编译器推断出关联的presenter
和view
的正确类型,例如:
class BasePresenter : VIPERPresenterProtocol {
var view : BaseView!
}
class BaseView : VIPERViewProtocol {
var presenter: BasePresenter!
}
var p = BasePresenter()
// p.view is correctly recognized as BaseView!
只要您使用关联类型,此选项就有效。由于Swift中没有covariance属性,如果你改变它,上面的代码将无法编译:
protocol VIPERViewProtocol : _VIPERViewProtocol {
var presenter: _VIPERPresenterProtocol! {get set}
}
无论如何,回到VIPER架构,这只会给具体类提供一个他们必须实现的模板。 如果我们可以定义一个“构建器”方法,使得通用对象符合协议(线框,演示者......),并连接所有组件,那将会更有用。
不幸的是,这样的事情不起作用:
func builder(p:VIPERPresenterProtocol, v:VIPERViewProtocol) {
p.view = v
v.presenter = p
}
编译器抱怨Protocol 'VIPERViewProtocol' can only be used as a generic constraint because it has Self or associated type requirements
。
也许一个可以探索的解决方案是泛型,但我仍然需要考虑它。