Can protocol be extended with function that would be defined by implementer in Swift?

Viewed 98

Example:

Playground: github

protocol A: class {}

extension A {
    func someFunc() {
        print("1")
    }
}

class B {
    weak var delegate: A?
    
    func someTrigger() {
        delegate?.someFunc()
    }
}

class C: A {
    lazy var b: B = {
        let b = B()
        b.delegate = self
        return b
    }()
    
    func someFunc() {
        print("2")
    }
    
    init() {
        b.someTrigger()
    }
}

let c = C()
/// printed 1

Question

Here above you can see an example to better understand the question. So the question is: Can protocol be extended with function that would be defined by implementer(class that implements protocol)? In my opinion result of example code is unexpected. Can it be done in some way without protocol inheritance?


Update

I can't implement someFunc() in protocol A(it's UIKit protocol). That is why I'm considering exactly this kind of architecture/configuration.

2 Answers
protocol A: class {
   func someFunc()
}

extension A {
    func someFunc() {
        print("1")
    }
}

class AA: A { }

Now in class AA you can use either default implementation (in the extension), or override it with a custom one. So you have to define a function in a protocol itself, since it's the interface.

But it doesn't make sense not to define it in a protocol, that's just a bad design, because protocol = interface on the class. If you want to use a function someFunc() - you can do it right away without redeclaring it, because it's already in there since you implemented a protocol.

Think of extending a protocol without exposing a function in the protocol itself like extending the class in which you are going to implement this protocol.

Update:

protocol MyProtocol: class {
 func myFunc()
} 
extension MyProtocol where Self: UIKitProtocol {
 func myFunc() {
 }
}

class AA: UIKitProtocol, MyProtocol { }

Define your own protocol

After some test that I tried a while ago, you have to expose the someFunc() function in the A protocol declaration, in order for the someFunc() function of the C class to get called like this:

protocol A: class {
    func someFunc()
}

Then you will have the following result:

let c = C()
/// printed 2

Update: You can instead of adding an extension to protocol A, to create another class that implements protocol A and use it for the default someFunc() implementation like this:

class D: A {
    func someFunc() {
        print("1")
    }
}

class B {
    weak var delegate: D?
    
    func someTrigger() {
        delegate?.someFunc()
    }
}

class C: D {
    lazy var b: B = {
        let b = B()
        b.delegate = self
        return b
    }()
    
    override func someFunc() {
        print("2")
    }
    
    override init() {
        super.init()
        b.someTrigger()
    }
}

This will also have your expected result.

Related