Search code examples
swiftclassprotocols

Swift, classes based on extended protocol don't conform to original protocol


These protocols are giving me nightmares.

I am trying to implement a couple protocols and classes conforming to them, such that I can have default implementations, but customized implementations are available by extending the protocols/classes. So far, this is what I have:

protocol ProtA {
    var aProperty: String { get set }
    var anotherProperty:String { get set }

    func aFunc (anArgument: String) -> String
}

protocol ProtB: ProtA {
    var aThirdProperty: String { get set }
}

protocol ProtC {
    func doSomething(parameter: Int, with anotherParameter: ProtA)
}

class ClassA: ProtA {
    var aProperty: String = "Hello, I'm a String."
    var anotherProperty: String = "I'm not the same String."

    func aFunc (anArgument: String) -> String {
        return anArgument
    }
}

class ClassB: ProtB {

    var aProperty: String = "Hello, I'm a String."
    var anotherProperty: String = "I'm not the same String."
    var aThirdProperty: String = "I'm yet another String!"

    func aFunc (anArgument: String) -> String {
        return anArgument
    }
}



class ClassC: ProtC {

func doSomething(parameter: Int, with anotherParameter: ProtA) {
    print (anotherParameter.aProperty) // Works fine.

}

}

Then, if I do

class ClassC: ProtC {

    func doSomething(parameter: Int, with anotherParameter: ProtA) {
        print (anotherParameter.aProperty) // Works fine.

    }

}

But, if I do

class ClassD: ProtC {

    func doSomething(parameter: Int, with anotherParameter: ProtA) {

        print (anotherParameter.aThirdProperty) // Value of type 'ProtA' has no member 'aThirdProperty'

    }

}

and, if instead I do

class ClassE: ProtC {

    func doSomething(parameter: Int, with anotherParameter: ProtB) {

        print (anotherParameter.aThirdProperty) // Type 'ClassE' does not conform to protocol 'ProtC'

    }

}

What am I doing wrong?


Solution

  • There's nothing wrong. You should just make sure that the declarations are semantically consistent. You should either create ProtD declaring the method with a ProtB parameter OR unwrapping the gotten ParamA parameter to use it as ProtB.

    func doSomething(parameter: Int, with anotherParameter: ProtB) {
         if let a = anotherParameter as? ProtA {
              print (a.aThirdProperty)
         }
    
    }