Set and protocols in Swift Set and protocols in Swift ios ios

Set and protocols in Swift


The immediate reason why you can't do what you want to do is that Hashable is a generic protocol. Thus it — or a protocol that derives from it — cannot be used as a Set's element type. A generic type can used only as a constraint in another generic. You will notice that you can't declare a Set<Hashable> either, even though a set's element type must conform to Hashable.

The simplest approach is to make, not a set of protocols, but a set of some object type. For example, if S is a struct that conforms to CustomProtocol (because it conforms to Hashable plus whatever else CustomProtocol entails), you can declare a set of S.

Example:

protocol CustomProtocol: Hashable {}func ==(lhs:S,rhs:S) -> Bool {    return lhs.name == rhs.name}struct S : CustomProtocol {    var name : String    var hashValue : Int { return name.hashValue }}let set = Set<S>()

If the problem you're trying to solve is that you want a collection of mixed types which are nevertheless in some way equatable to one another, then that is the very same problem solved by protocol extensions, as explained by the discussion in the Protocol-Oriented WWDC 2015 video.

But it would be simpler just to make all your types classes that derive from NSObject. You can still make them adopt some secondary protocol, of course, but the set won't be defined as a set of that protocol but of NSObject.


In Swift 3, one solution is to use the AnyHashable structure.

For instance, to create a Observers/Observable pattern, we could do :

protocol Observer {    func observableDidSomething(_ observable: Observable)}class Observable {    private var observersSet: Set<AnyHashable> = []    private var observers: [Observer] {        return observersSet.flatMap { $0 as? Observer }    }    func add<O>(_ observer: O) where O : Observer, O : Hashable {        observersSet.insert(observer)    }    func remove<O>(_ observer: O) where O : Observer, O : Hashable {        observersSet.remove(observer)    }    // ...    private func doSomething() {        // do something ...        observers.forEach { $0.observableDidSomething(self) }    }} 

Notice that I separate the Hashable protocol from my protocol Observer.