I've started to learn swift after Java. In Java I can use any object as a key for HashSet, cause it has default hashCode and equals based on object identifier. How to achieve the same behaviour in Swift?
In Swift, a Hashable is a protocol that provides a hashValue to our object. The hashValue is used to compare two instances. To use the hashValue , we first have to conform (associate) the type (struct, class, etc) to Hashable property.
You can use any type that conforms to the Hashable protocol in a set or as a dictionary key. Many types in the standard library conform to Hashable : Strings, integers, floating-point and Boolean values, and even sets are hashable by default.
NSObjectProtocol doesn't inherit from Hashable .
To conclude, a hashable protocol allows us to create custom types that can be compared for it's equality using it's hashValue . In this way we are able to use our custom type in a set or as a key in a dictionary while ensuring that it has a unique value.
If you are working with classes and not structs, you can use the ObjectIdentifier struct. Note that you also have to define == for your class in order to conform to Equatable (Hashable requires it). It would look something like this:
class MyClass: Hashable { } func ==(lhs: MyClass, rhs: MyClass) -> Bool { return ObjectIdentifier(lhs) == ObjectIdentifier(rhs) } class MyClass: Hashable { var hashValue: Int { return ObjectIdentifier(self).hashValue } }
In Swift, the type must conform to Hashable and Equatable for it to be used in a data structure such as a Dictionary or a Set. However, you can add "automatic conformance" by using the "object identifier" of the object. In the code below, I implemented a reusable class to do this automatically.
Note, Swift 4.2 changed how Hashable is implemented, so you no longer override hashValue. Instead, you override hash(into:).
open class HashableClass { public init() {} } // MARK: - <Hashable> extension HashableClass: Hashable { public func hash(into hasher: inout Hasher) { hasher.combine(ObjectIdentifier(self)) } // `hashValue` is deprecated starting Swift 4.2, but if you use // earlier versions, then just override `hashValue`. // // public var hashValue: Int { // return ObjectIdentifier(self).hashValue // } } // MARK: - <Equatable> extension HashableClass: Equatable { public static func ==(lhs: HashableClass, rhs: HashableClass) -> Bool { return ObjectIdentifier(lhs) == ObjectIdentifier(rhs) } } To use, just take your class and subclass HashableClass, then everything should just work!
class MyClass: HashableClass { }
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