I'm trying to implement a protocol that itself inherits multiple protocols that both have a delegate member. Is there a clean way to do this without needing different names for the delegate of each protocol?
protocol ProtocolOne {
var delegate: ProtocolOneDelegate?
}
protocol ProtocolTwo {
var delegate: ProtocolTwoDelegate?
}
protocol CombinedProtocol: ProtocolOne, ProtocolTwo {
}
protocol CombinedDelegate: ProtocolOneDelegate, ProtocolTwoDelegte {
}
class ProtocolImpl: CombinedProtocol {
// How can I implement delegate here?
// I've tried the following options without success:
var delegate: CombinedDelegate?
var delegate: protocol<ProtocolOneDelegate, ProtocolTwoDelegate>?
}
You should be able to combine them in one:
var delegate: (ProtocolOneDelegate & ProtocolTwoDelegate)?
You can now use both protocols.
In your code, delegate
is just a normal property. You can have multiple protocols declaring a property with the same name and same type, and have a class directly or indirectly implement it.
If different protocols define a property with the same name but different type, you won't be able to make it compile, because the compiler will complain for redeclaration of a property and class not confirming to one of the protocols.
There are 2 possible solution. The most obvious one is to avoid using names having high probability of being used in other protocols - delegate
is a typical case. Use a different naming convention, such as protocol1Delegate
, dataSourceDelegate
, apiCallDelegate
, etc.
The 2nd solution consists of replacing properties with methods. For example:
protocol P1 {
func test() -> String?
}
protocol P2 {
func test() -> Int?
}
protocol P3: P1, P2 {
}
class Test : P3 {
func test() -> String? { return nil }
func test() -> Int? { return nil }
}
Swift consider functions with the same parameters list but different return type as overloads. Note however that if 2 protocols use the same function signature (name, parameters and return type), when implementing in the class you will implement that function once - that might be the wanted behavior in some cases, but unwanted in other cases.
A solution might be to use protocol extensions (check extension Combined
). The benefit is that Combined
only declares delegate
and oneDelegate
and twoDelegate
are computed cross-implementation. Unfortunately, it's a requirement to have the three variables exposed out of the class, that might be inconvenient.
// MARK: - Delegates protocols
protocol OneDelegate {
func oneDelegate(one: One)
}
protocol TwoDelegate {
func twoDelegate(two: Two)
}
protocol CombinedDelegate: OneDelegate, TwoDelegate {
func combinedDelegate(combined: Combined)
}
// MARK: - Model protocols
protocol One: class {
var oneDelegate: OneDelegate? { get }
}
protocol Two: class {
var twoDelegate: TwoDelegate? { get }
}
protocol Combined: One, Two {
var delegate: CombinedDelegate? { get }
}
extension Combined {
var oneDelegate: OneDelegate? {
return delegate
}
var twoDelegate: TwoDelegate? {
return delegate
}
}
// MARK: - Implementations
class Delegate: CombinedDelegate {
func oneDelegate(one: One) {
print("oneDelegate")
}
func twoDelegate(two: Two) {
print("twoDelegate")
}
func combinedDelegate(combined: Combined) {
print("combinedDelegate")
}
}
class CombinedImpl: Combined {
var delegate: CombinedDelegate?
func one() {
delegate?.oneDelegate(self)
}
func two() {
delegate?.twoDelegate(self)
}
func combined() {
delegate?.combinedDelegate(self)
}
}
// MARK: - Usage example
let delegate = Delegate()
let protocolImpl = CombinedImpl()
protocolImpl.delegate = delegate
protocolImpl.one()
protocolImpl.two()
protocolImpl.combined()
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With