Search code examples
swiftpolymorphismprotocols

Swift protocols behavior


Let's assume I have protocol FooProtocol in Swift with one method with its default implementation:

protocol FooProtocol {
    func foo()
}

extension FooProtocol {
    func foo() {
        print("protocol")
    }
}

and class FooClass with cast instance:

class FooClass : FooProtocol {
    func foo() {
        print("class")
    }
} 

let A = FooClass() as FooProtocol
A.foo()

As expected, "class" will be printed in console. However, if I make foo() method of my protocol being optional - "protocol" will be printed instead.

@objc protocol FooProtocol {
    @objc optional func foo() 
}

But if I call A.foo?() rather than A.foo() - "class" will be printed again.

I wonder, just for theoretical purposes, what the hell is happening here? Any explanations are appreciated.


Solution

  • You cannot call optional protocol method without optional chaining. I.e. if you comment out

    extension FooProtocol {
        func foo() {
        ...
    

    and you try to call A.foo(), you will get a compilation error:

    value of optional type '(() -> ())?' must be unwrapped to a value of type '() -> ()'

    As you see the signature of optional is not even the same as non-optional. So by calling A.foo(), you are not calling method you implemented, you are calling default protocol implementation directly.

    It also makes sense since primary reason for @objc optional is interpolation with Objective C, where default protocol implementation won't be visible. So relying on protocol function for objc function would produce different result on swift and objective c, which is undesired.

    I cannot say if there's any loophole to use both optional and default protocol implementation on the same function. But question is: do you really need it?

    If you are concerned with interpolation, you need equal solution for both Swift and Objective c, and that means you rather need basic protocol implementation, which both Swift and objc can inherit

    If you need no interpolation, you don't really need optional, and can rely on default protocol implementation alone.