Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Swift implement multiple protocols with a delegate

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>?
}
like image 645
robhasacamera Avatar asked Nov 23 '14 03:11

robhasacamera


3 Answers

You should be able to combine them in one:

var delegate: (ProtocolOneDelegate & ProtocolTwoDelegate)?

You can now use both protocols.

like image 124
Travis M. Avatar answered Oct 14 '22 06:10

Travis M.


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.

like image 37
Antonio Avatar answered Oct 14 '22 05:10

Antonio


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()
like image 21
atxe Avatar answered Oct 14 '22 07:10

atxe