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