Swift: 'Hashable.hashValue' is deprecated as a protocol requirement;
Asked Answered
A

2

49

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

Antineutrino answered 28/3, 2019 at 10:22 Comment(3)
see this for help:hashable-enhancementsMungovan
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.Litotes
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.Dialectal
P
74

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
        }
    }
}
Pitre answered 28/3, 2019 at 10:30 Comment(1)
if you remove hashable as a type (from the extension/class) you can also get rid of the warningLandscapist
A
13

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)
    }

}
Absalom answered 23/10, 2022 at 4:16 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.