1

I have a NSObject consisting of a bunch of properties. The NSObject can uniquely be identified using a Date property and a String property. What is the best way to create a hash using these two variables?

I could do something like date.hashValue ^ string.hashValue, but it seems the hashes differ for each object.

The object looks like this:

class Something : Model {
    public var name: String!
    public var time: Date!

    override var hash : Int {
       return time.hashValue ^ name.hashValue
    }
}
Hedam
  • 2,209
  • 27
  • 53
  • 1
    Unrelated but you are strongly discouraged from declaring properties IUO as a workaround not to write an initializer. – vadian Aug 11 '19 at 19:23
  • Thanks for the tip. I will refactor in that improvement as soon as possible. – Hedam Aug 11 '19 at 19:45

1 Answers1

5

For NSObject subclasses you must override the hash property and the isEqual: method, compare NSObject subclass in Swift: hash vs hashValue, isEqual vs ==.

For the implementation of the hash property you can use the Hasher class introduced in Swift 4.2, and its combine() method:

Adds the given value to this hasher, mixing its essential parts into the hasher state.

I would also suggest to make the properties constant, since mutating them after an object is inserted into a hashable collection (set, dictionary) causes undefined behaviour, compare Swift mutable set: Duplicate element found.

class Model: NSObject { /* ... */ }


class Something : Model {
    let name: String
    let time: Date

    init(name: String, time: Date) {
        self.name = name
        self.time = time
    }

    override var hash : Int {
        var hasher = Hasher()
        hasher.combine(name)
        hasher.combine(time)
        return hasher.finalize()
    }

    static func ==(lhs: Something, rhs: Something) -> Bool {
        return lhs.name == rhs.name && lhs.time == rhs.time
    }
}
Martin R
  • 529,903
  • 94
  • 1,240
  • 1,382