Make your custom types easier to use by ensuring that they conform to Swift protocols.
Overview
When using custom types to model data in your programs, you may frequently need to check whether two values are the same or different, or whether a particular value is included in a list of values. This capability, as well as the ability to store values in a set or use them as keys in a dictionary, are governed by two related standard library protocols, Equatable
and Hashable
.
You can compare instances of an equatable type by using the equal-to (
==
) and not-equal-to (!=
) operators.An instance of a hashable type can reduce its value mathematically to a single integer, which is used internally by sets and dictionaries to make lookups consistently fast.
Many standard library types are both equatable and hashable, including strings, integers, floating-point values, Boolean values, and collections of equatable and hashable types. The ==
comparison and the contains(_:)
method call in the following example depend on strings and integers being equatable:
Conforming to the Equatable
and Hashable
protocols is straightforward and makes it easier to use your own types in Swift. It's a good idea for all your custom model types to conform.
Conform Automatically to Equatable and Hashable
You can make many custom types equatable and hashable by simply declaring these protocol conformances in the same file as the type's original declaration. Add Equatable
and Hashable
to the list of adopted protocols when declaring the type, and the compiler automatically fills in the requirements for the two protocols:
With Equatable
conformance, you can use the equal-to operator (==
) or the not-equal-to operator (!=
) with any two instances of the Position
type.
Hashable
conformance means that you can store positions in a set and quickly check whether you've visited a position before, as shown in the following example:
In addition to simplifying your code, this automatic conformance reduces errors, because any new properties you add to your custom types are automatically included when hashing and testing for equality. A type is eligible for automatic conformance to Equatable
and Hashable
when it's a structure or an enumeration that meets these criteria:
For a structure, all its stored properties must conform to
Equatable
andHashable
.For an enumeration, all its associated values must conform to
Equatable
andHashable
. (Enumerations without associated values haveEquatable
andHashable
conformance even without declaring adoption.)
Conform Manually to Equatable and Hashable
You need to manually implement Equatable
and Hashable
conformance for a type in these cases:
The type doesn't meet the criteria listed in the previous section.
You want to customize the type's conformance.
You want to extend a type declared in another file or module to conform.
The Player
type is a class, so it doesn't qualify for automatic synthesis of the Equatable
or Hashable
requirements. To make this class conform to the Equatable
protocol, declare conformance in an extension and implement the static ==
operator method. Compare each significant property for equality in your ==
method's implementation:
To make Player
conform to the Hashable
protocol, declare conformance in another extension and implement the hash(into:)
method. In the hash(into:)
method, call the combine(_:)
method on the provided hasher with each significant property:
Use All Significant Properties for Equatable and Hashable
When implementing the ==
method and the hash(into:)
method, use all the properties that affect whether two instances of your custom type are considered equal. In the implementations above, the Player
type uses name
and position
in both methods.
If your type contains properties that don't affect whether two instances are considered equal, exclude those properties from comparison in the ==
method and from hashing in hash(into:)
. For example, a type might cache an expensive computed value so that it only needs to calculate it once. If you compare two instances of that type, whether or not the computed value has been cached shouldn't affect their equality, so the cached value should be excluded from comparison and hashing.
Important
Always use the same properties in both your ==
and hash(into:)
methods. Using different groups of properties in the two methods can lead to unexpected behavior or performance when using your custom type in sets and dictionaries.
Customize NSObject Subclass Behavior
NSObject
subclasses inherit conformance to the Equatable
and Hashable
protocols, with equality based on instance identity. If you need to customize this behavior, override the is
method and hash
property instead of the ==
operator method and hash
property.
As noted in the previous section, two instances that are considered equal must have the same hash value. If you override one of these declarations, you must also override the other to maintain that guarantee.