Making conform to Hashable is not difficult for class, struct or enum.
You just need to explicitly declare conformance to Hashable and define a property hashValue: Int. Practically, the hashValue needs to fulfill one simple axiom: if a == b then a.hashValue == b.hashValue.
(To conform Hashable, you also need to make the type Equatable. In case of CGPoint, it is already Equatable.)
An example to make CGPoint conform to Hashable:
extension CGPoint: Hashable {
public var hashValue: Int {
//This expression can be any of the arbitrary expression which fulfills the axiom above.
return x.hashValue ^ y.hashValue
}
}
var pointDict: [CGPoint: String] = [
CGPoint(x: 1.0, y: 2.0): "PointA",
CGPoint(x: 3.0, y: 4.0): "PointB",
CGPoint(x: 5.0, y: 6.0): "PointC",
]
print(pointDict[CGPoint(x: 1.0, y: 2.0)]) //->Optional("PointA")
As CGPoint contains CGFloat values, so, CGPoint as Key of Dictionary may cause unexpected behavior based on the calculation error of binary floating-point system. You need to use it with extra caution.
ADDITION
If you want to avoid some calculation error issue and can accept that the structure can only contain Ints, you can define your own struct and make it conform to Hashable:
struct MyPoint {
var x: Int
var y: Int
}
extension MyPoint: Hashable {
public var hashValue: Int {
return x.hashValue ^ y.hashValue
}
public static func == (lhs: MyPoint, rhs: MyPoint) -> Bool {
return lhs.x == rhs.x && lhs.y == rhs.y
}
}
var myPointDict: [MyPoint: String] = [
MyPoint(x: 1, y: 2): "MyPointA",
MyPoint(x: 3, y: 4): "MyPointB",
MyPoint(x: 5, y: 6): "MyPointC",
]
print(myPointDict[MyPoint(x: 1, y: 2)]) //->Optional("MyPointA")
Not much more difficult than the code above, one more thing you need is just defining == operator for the struct. Please make it a try.