0

Could someone explain why won't the following example compile? Am I missing something trivial?

protocol Coordinator {}

protocol Coordinatable {
    var coordinator: Coordinator { get set }
}

class ExampleCoordinator: Coordinator {}

class ViewController: UIViewController, Coordinatable {
    var coordinator: ExampleCoordinator!
}

The error is:

Type 'ViewController' does not conform to protocol 'Coordinatable'

Thanks!

2
  • 1
    Does this answer your question? Protocol variable implementing another protocol (also note that you are providing an optional when the protocol requires a non-optional) Commented May 20, 2020 at 20:58
  • It also does, thank you! Commented May 21, 2020 at 8:19

2 Answers 2

1

Replace var coordinator: ExampleCoordinator! with var coordinator: Coordinator. You are trying to conform to Coordinatable so you have to implement it's properties.

EDIT:

import UIKit
protocol Coordinator {}

protocol Coordinatable {
    var coordinator: Coordinator { get set }
}

class ExampleCoordinator: Coordinator {}

class ViewController: UIViewController, Coordinatable {
    var coordinator: Coordinator

    init(coordinator: Coordinator) {
        self.coordinator = coordinator
        super.init(nibName: nil, bundle: nil)
    }

    // ignore this, it has nothing to do with the question/answer
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

let testVC = ViewController(coordinator: ExampleCoordinator()) // works
Sign up to request clarification or add additional context in comments.

3 Comments

But ExampleCoordinator implements Coordinator, so I am implicitly implementing the required property.
Well the protocol requires you to implement a Coordinator not an ExampleCoordinator. So do what I described above and then pass an ExampleCoordinator during the initialisation and set self.coordinator to this very ExampleCoordinator
I updated my answer a bit to make it more clear :) (Just paste it into a playground a play with it)
0

The reason that it doesn't work

Assuming your code would work and we write additionally

class ExampleCoordinator2: Coordinator {}

val viewController = ViewController()
viewController.coordinator = ExampleCoordinator2()

The assignment to coordinator cannot work since ExampleCoordinator2 is not a subclass of ExampleCoordinator.

So, just considering the types the following code should work but the Swift compiler doesn't allow it (this might work in the future):

protocol Coordinatable {
    var coordinator: Coordinator { get } // removing the `set`
}

class ViewController: UIViewController, Coordinatable {
    var coordinator: ExampleCoordinator! // still an error
}

Possible solutions

Using var coordinator: Coordinator in ViewController

class ViewController: UIViewController, Coordinatable {

    var coordinator: Coordinator

    init(coordinator: Coordinator) {
        self.coordinator = coordinator
        super.init(nibName: nil, bundle: nil)
    }

    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

Using only { get } in Coordinatable

protocol Coordinatable {
    var coordinator: Coordinator { get } // removing the `set`
}

class ViewController: UIViewController, Coordinatable {
    // computed property
    var coordinator: Coordinator {
        // implicit return
        exampleCoordinator
    }
    var exampleCoordinator: ExampleCoordinator!
}

Using an associatedtype in Coordinatable

protocol Coordinatable {
    associatedtype C: Coordinator
    var coordinator: C { get set }
}

class ViewController: UIViewController, Coordinatable {
    
    var coordinator: ExampleCoordinator
    
    init(coordinator: ExampleCoordinator) {
        self.coordinator = coordinator
        super.init(nibName: nil, bundle: nil)
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

This has however a big disadvantage that you cannot have a heterogenous array of type [Coordinatable] since Coordinatable has an associatedtype. And still, you cannot assign a value of type ExampleCoordinator2.

You can only write generic code over <C: Coordinatable>. E.g.

func printCoordinators<C: Coordinatable>(coordinatables: [C]) {
    
    coordinatables.forEach {
        print($0.coordinator)
    }
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.