Search code examples
swiftprotocolsswift-protocols

Protocol inheritance with associated type


I have a base protocol that describes the router behavior:

protocol BaseRouterProtocol: AnyObject {
    associatedtype View: MainView
    func dismiss(viewController: ViewController<View>?)
}

extension BaseRouterProtocol {
    func dismiss(viewController: ViewController<View>?) {
        viewController?.navigationController?.popViewController(animated: true)
    }
}

I want to adopt this protocol to another like this:

protocol StartRouterProtocol: BaseRouterProtocol where View == StartView {
    func showTermsVC()
    func showSignInVC()
}

But when I create a variable of this type:

let router: StartRouterProtocol

Compiler throws me an error:

Protocol 'StartRouterProtocol' can only be used as a generic constraint because it has Self or associated type requirements

Why does this happening if I have described the type that I expect?


Solution

  • Once a protocol has an associated type, that protocol can't be used as a type by itself for instance declarations-- only for generic constraints and declaring conformance.

    So in this case, Swift is saying "yeah, but what is the concrete type for StartRouterProtocol's associated type?"

    In this case, it's asking you to either:

    1. Use a concrete type directly, i.e. let router: MyStartViewClass with this conformance declaration, elsewhere: class MyStartViewClass: StartRouterProtocol { ... })
    2. OR, push the need for a concrete type up one layer, as a generic constraint i.e.
    class MyRouterController<T: StartRouterProtocol> {
        let router: T
    }
    

    This is probably not what you were hoping for, but unfortunately associated types add complexity to how you use protocols, especially if you're familiar with generics & interfaces from other languages. (i.e. Java/C# interfaces)

    You can work around some aspects of associated types by using a concept called "type erasure" -- but that can cause other problems and complexity.

    Here's some further reading that may help: https://medium.com/monstar-lab-bangladesh-engineering/swift-from-protocol-to-associatedtype-then-type-erasure-a4093f6a2d08