How to use a custom class type to be the key in Dictionary in Swift?

Continuing on with what Andy Ibanez posted. A shortcut to implementing a hashValue is to piggyback off String's hashValue. You could do something like this.

class Pixel: Hashable {
    var r:Int = 0;
    var g:Int = 0;
    var b:Int = 0;
    var a:Int = 0;

    var hashValue: Int {
        get {
            return "\(r)\(g)\(b)\(a)".hashValue;
        }
    }
}

You also need an Equatable function because hashValues in this case are merely a quick check for verifying two objects are not equal. Since it is possible for two objects to have the same hashValue, but not be equal, you still need to implement == to define equality like below.

func ==(lhs: Pixel, rhs: Pixel) -> Bool{
    if lhs.r != rhs.r{
        return false;
    }
    if lhs.g != rhs.g{
        return false;
    }
    if lhs.b != rhs.b{
        return false;
    }
    if lhs.a != rhs.a{
        return false;
    }
    return true;
}

Any custom type that you want to use a dictionary key must conform with the Hashable protocol.

This protocol has one property that you must implement.

var hashValue: Int { get }

Use this property to generate an int that Dictionary can use for lookup reasons. You should try to make it so the generated hashValue is unique for each pixel.

The Swift book has the following note, so you can probably make a random hash (as long as it's unique):

The value returned by a type's hashValue property is not required to be the same across different executions of the same program, or in different programs.

Note that because Hashable inherits from Equatable you must also implement:

func ==(_ lhs: Self, _ rhs: Self) -> Bool.

I'm not sure what the internal structure of your pixel is, but you could probably consider two pixels equal when both have the same "x" and "y" values. The final logic is up to you.

Modify this as you need:

struct Pixel : Hashable {

    // MARK: Hashable
    var hashValue: Int {
        get {
            // Do some operations to generate a unique hash.
        }
    }
}

//MARK: Equatable
func ==(lh: Pixel, rh: Pixel) -> Bool {
    return lh.x == rh.x && rh.y == lh.y
}

Implement the Hashable protocol like this:

class Pixel : Hashable {
    var alpha, red, green, blue : Int

    init(red: Int, green: Int, blue: Int, alpha: Int) {
        self.red = red
        self.green = green
        self.blue = blue
        self.alpha = alpha
    }

    var hashValue : Int {
        get {
            return alpha ^ red ^ green ^ blue
        }
    }
}

func ==(lhs: Pixel, rhs: Pixel) -> Bool {
    return lhs.alpha == rhs.alpha && lhs.red == rhs.red && lhs.green == rhs.green && lhs.blue == rhs.blue
}

From swift 4.2, hashValue is deprecated as a Hashable requirement.

Now if you want to customize how your type implements Hashable, you can override the hash(into:) method instead of hashValue. The hash(into:) method passes a Hasher object by reference, which you call combine(_:) on to add the essential state information of your type.

class Pixel {
    var alpha, red, green, blue : Int
}

// Hashable implementation
extension Pixel : Hashable {
    func hash(into hasher: inout Hasher) {
        hasher.combine(self.red)
        hasher.combine(self.green)
        hasher.combine(self.blue)
        hasher.combine(self.alpha)
    }
}