46

I've been facing following issue (it's just a warning) with my iOS project.

'Hashable.hashValue' is deprecated as a protocol requirement; conform type 'ActiveType' to 'Hashable' by implementing 'hash(into:)' instead

  • Xcode 10.2
  • Swift 5

Source Code:

public enum ActiveType {
    case mention
    case hashtag
    case url
    case custom(pattern: String)

    var pattern: String {
        switch self {
        case .mention: return RegexParser.mentionPattern
        case .hashtag: return RegexParser.hashtagPattern
        case .url: return RegexParser.urlPattern
        case .custom(let regex): return regex
        }
    }
}

extension ActiveType: Hashable, Equatable {
    public var hashValue: Int {
        switch self {
        case .mention: return -1
        case .hashtag: return -2
        case .url: return -3
        case .custom(let regex): return regex.hashValue
        }
    }
}

enter image description here

Any better solution? The warning itself suggesting me to implement 'hash(into:)' but I don't know, how?

Reference: ActiveLabel

Dávid Pásztor
  • 51,403
  • 9
  • 85
  • 116
Krunal
  • 77,632
  • 48
  • 245
  • 261
  • 3
    see this for help:[hashable-enhancements](https://github.com/apple/swift-evolution/blob/master/proposals/0206-hashable-enhancements.md#hash-into) – Anbu.Karthik Mar 28 '19 at 10:30
  • 2
    Why do you overwrite the hashValue in the first place? The compiler can automatically synthetise `Hashable` conformance for your `enum`. You also don't need to explicitly state `Equatable` conformance, since `Hashable` inherits from `Equatable`, so when you declare `Hashable` conformance, `Equatable` methods are synthetised for you. – Dávid Pásztor Mar 28 '19 at 10:33
  • 1
    Background: `Hashable` moved away from asking conforming types for a `hashValue: Int` that describes themselves, to asking them to take in a `Hasher`, and "mix" themselves into it (by mixing in their fields). Previously people had difficulty deriving good hash values for objects with multiple fields, often resorting to hacks, like XORing all the elements (`a ^ b ^ c`), or worse, taking the string value of a string that concatinates the elements (`"\(a)-\(b)-\(c)".hashValue`). Now instead, you just tell the hasher what to hash, and it uses a proper hashing algorithm to do that on your behalf. – Alexander Nov 24 '19 at 19:13

2 Answers2

73

As the warning says, now you should implement the hash(into:) function instead.

func hash(into hasher: inout Hasher) {
    switch self {
    case .mention: hasher.combine(-1)
    case .hashtag: hasher.combine(-2)
    case .url: hasher.combine(-3)
    case .custom(let regex): hasher.combine(regex) // assuming regex is a string, that already conforms to hashable
    }
}

It would be even better (in case of enums and struct) to remove the custom hash(into:) implementation (unless you need a specific implementation) as the compiler will automatically synthesize it for you.

Just make your enum conforming to it:

public enum ActiveType: Hashable {
    case mention
    case hashtag
    case url
    case custom(pattern: String)

    var pattern: String {
        switch self {
        case .mention: return RegexParser.mentionPattern
        case .hashtag: return RegexParser.hashtagPattern
        case .url: return RegexParser.urlPattern
        case .custom(let regex): return regex
        }
    }
}
Rico Crescenzio
  • 3,952
  • 1
  • 14
  • 28
  • 1
    if you remove hashable as a type (from the extension/class) you can also get rid of the warning – itsmcgh Feb 21 '20 at 03:44
6

To implement the hash(into:) function instead:

public class JSONNull: Codable, Hashable {

    public var hashValue: Int {
        return 0
    }
}

Should be updated with this:

public class JSONNull: Codable, Hashable {

    public func hash(into hasher: inout Hasher) {
        hasher.combine(0)
    }

}
Claytog
  • 618
  • 8
  • 8