3

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.

pawello2222
  • 46,897
  • 22
  • 145
  • 209
えるまる
  • 2,409
  • 3
  • 24
  • 44

2 Answers2

2
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

Vitalii Shvetsov
  • 404
  • 2
  • 11
  • @Erumaru updated the answer, check it. So you have to create your own protocol and extend it where Self: A { } – Vitalii Shvetsov Aug 28 '20 at 10:22
  • Also you can do it without protocols at all, using composition, since you're not defining 'interfaces', but rather extending the functionality – Vitalii Shvetsov Aug 28 '20 at 10:24
  • Then, I need to implement `myFunc` in class `AA` as I mentioned in the question **implementer(class that implements protocol)**. I believe that question a bit unclear from beginning, my bad. Thanks for your time spending on updates! – えるまる Aug 28 '20 at 10:43
2

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.

gcharita
  • 7,729
  • 3
  • 20
  • 37