Search code examples
swiftswift2protocols

Swift: type does not conform to protocol


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

struct StructA: A {}
struct StructB {
    var a: StructA
}
extension StructB: B {}

This produces the error :

Type 'StructB' does not conform to protocol 'B'

The StructA already conform to protocol A, and StructB's property a return StructA type. That seems pretty a protocol B conformed type.

But why?


Xcode version 7.3 which Swift version is 2.2


Solution

  • To better illustrate the problem with your current code, let's say you have a StructC : A.

    Your protocol B says that you can assign StructC to a (as it conforms to A) – but StructB says you cannot assign StructC to a StructA type. Therefore StructB doesn't conform to B.

    The solution is either to change the type of a from StructA to A as Rahul says, or better yet, you could use generics.

    The advantage of using generics is once you create your StructB with a given a – that property's type will be inferred by Swift, giving you better type safety. For example, once you assign a StructA to it, its type will then be StructA. If you assign a StructC to it, its type will be StructC.

    To do this, we just have to add an associatedtype to protocol B. This will define a 'placeholder' type that we can then implement in a type that conforms to B. We can then define the generic type T in StructB that will provide the 'implementation' of AType – making sure it conforms to A. Therefore, we are now free to assign either StructA or StructC to a, without losing type safety.

    protocol A {}
    protocol B {
    
        // new associated type to hold the type of "a" which conforms to A
        associatedtype AType:A
        var a: AType { get }
    }
    
    struct StructA: A {}
    struct StructC:A {}
    
    // define the new generic T which conforms to A
    struct StructB<T:A> {
    
        // define the type of a as the generic T, which conforms to A (and thus conforms with the protocol)
        var a : T
    }
    
    extension StructB: B {}
    
    let s = StructB(a: StructA())
    s.a // "a" is now of type StructA
    
    let s1 = StructB(a: StructC())
    s1.a // "a" is now of type StructC