Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Cyclic loop between protocols in swift

I'm trying to define some protocols in a Swift file, however I've noticed that if the protocols have crossed references XCode becomes buggy and it's impossible to work with the project. The example of used protocols might be the one used below:

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 }
}

Where the VIPERPresenterProtocol has a reference to the VIPERViewProtocol and this last has a reference to the VIPERPresenterProtocol.

This is something that works in Objective-C but that Swift doesn't like. My question is, is this something Apple doesn't expect to support in Swift, if it might be a bug of the Swift language or if I should implement this in any other way.

like image 729
Pedro Piñera Buendia Avatar asked Jun 10 '26 07:06

Pedro Piñera Buendia


1 Answers

Your question has a form of:

protocol A
{
    var b: B? { get set }
}

protocol B
{
    var a: A? { get set }
}

However, while the two protocol declarations compile, any attempt to implement them as such does not:

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?
}

This does not happen if we break the cycle:

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}

Or if we define the two protocols in terms of concrete types:

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"}}

My impression is that the type checker cannot yet deal with recursive type declarations. Whether it ever will, may be an open question even to Apple at this point, though, because of the clear intention to facilitate functional idioms, this must at least be a possibility.

I have answered a similar question before, though, as I eventually realised with the help of @newacct, not identical.

EDIT

I have just upgraded to Xcode 6.1 GM Seed and things have changed! The following snippet now compiles and appears to run fine!

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         // --> {{{...}}}

(This improvement, however, does not extend to recursively defined associated types.)

like image 174
Milos Avatar answered Jun 13 '26 16:06

Milos