NSObject
は自身がEquatable
なので、==
やEquatable
に対するメソッドが呼べたりするのですが、デフォルトの動作はポインタを比較するSwiftでいう===
相当なので気をつけましょう。
final class Hoge: NSObject { let value: Int init(_ value: Int) { self.value = value } } print(Hoge(1) == Hoge(1)) // false
インスタンスとしては別のものなので、上記コードの比較の結果はfalse
になります。
解決策
NSObject
を継承したクラスでは、比較の際にNSObjectProtocol
のisEqual
が呼ばれるので、そちらをoverrideすることで、意図した比較を行うことができます。
value
で比較したい場合は以下のようになります。
override func isEqual(_ object: Any?) -> Bool { guard let other = object as? Hoge else { return false } return value == other.value }
NSObject
はHashable
でもあるのでそちらも整合させるようにします。(オブジェクトの==
が成り立つ場合、hashValue
も同じでなければなりません。)
isEqual
と同様に、hash
をoverrideすることで、Hashable
で使われるハッシュ値を変更することができます。
override var hash: Int { var hasher = Hasher() value.hash(into: &hasher) return hasher.finalize() }
全体のコードはこのようになります。
final class Hoge: NSObject { let value: Int init(_ value: Int) { self.value = value } override var hash: Int { var hasher = Hasher() value.hash(into: &hasher) return hasher.finalize() } override func isEqual(_ object: Any?) -> Bool { guard let other = object as? Hoge else { return false } return value == other.value } } let hoge1 = Hoge(1) let hoge2 = Hoge(1) print(hoge1 == hoge2) // true print(hoge1.hashValue == hoge2.hashValue) // true
雑記
転職して結構コード書いてたので、ストレスが減って最近ブログ書いてませんでした。
無駄なNSObject
継承はやめよう 👊