Now I understand it. What I don't understand is why there is nowhere metioning this. All docs are talking about Hashable, clearly that NSObject didn't rely on it.
Zhaoxin Get Outlook for iOS<https://aka.ms/o0ukef> ________________________________ From: Saagar Jha <saa...@saagarjha.com> Sent: Wednesday, March 29, 2017 11:47:51 AM To: Zhao Xin Cc: Swift Users List Subject: Re: [swift-users] Set with element of NSObject subclasses didn't work as expected NSObject’s hash (which Set uses) is done via ObjectIdentifier, which IIRC uses something along the lines of the object's address. That’s why you’re getting the behavior you’re seeing. Saagar Jha On Mar 28, 2017, at 20:20, Zhao Xin via swift-users <swift-users@swift.org<mailto:swift-users@swift.org>> wrote: Turns out that for `NSObject`, protocol `Equatable` wasn't used. Instead, it used `NSObjectProtocol.isEqual(_ object: Any?)`. Also, override `func isEqual(_ object: Any?) -> Bool` requires to override `var hash: Int { get }` as well. I think this behavior should be mentioned in Swift docs or manual in `Set` section. Below code works. class Bar:NSObject { let value:Int override public var hashValue: Int { return value } public static func ==(lhs: Bar, rhs: Bar) -> Bool { return lhs.value == rhs.value } // required by NSObjectProtocol override func isEqual(_ object: Any?) -> Bool { if let rhs = object as? Bar { return self == rhs } return false } override var hash: Int { return self.hashValue } init(_ value:Int) { self.value = value } } let barSetA:Set = [Bar(8), Bar(9)] let barSetB:Set = [Bar(9), Bar(10)] let barResultC = barSetA.intersection(barSetB) // {{NSObject, value 9}} let barResultD = barSetA.subtracting(barSetB) // {{NSObject, value 8}} Gladly I find it here<http://stackoverflow.com/questions/32726524/swift-2-0-set-not-working-as-expected-when-containing-nsobject-subclass>. Zhaoxin On Wed, Mar 29, 2017 at 3:50 AM, Zhao Xin <owe...@gmail.com<mailto:owe...@gmail.com>> wrote: Please see the code first. import Foundation class Foo:Hashable { let value:Int public var hashValue: Int { return value } public static func ==(lhs: Foo, rhs: Foo) -> Bool { return lhs.value == rhs.value } init(_ value:Int) { self.value = value } } let fooSetA:Set = [Foo(8), Foo(9)] let fooSetB:Set = [Foo(9), Foo(10)] let fooResultC = fooSetA.intersection(fooSetB) // {{value 9}} let fooResultD = fooSetA.subtracting(fooSetB) // {{value 8}} class Bar:NSObject { let value:Int override public var hashValue: Int { return value } public static func ==(lhs: Bar, rhs: Bar) -> Bool { return lhs.value == rhs.value } init(_ value:Int) { self.value = value } } let barSetA:Set = [Bar(8), Bar(9)] let barSetB:Set = [Bar(9), Bar(10)] let barResultC = barSetA.intersection(barSetB) // Set([]) let barResultD = barSetA.subtracting(barSetB) // {{NSObject, value 9}, {NSObject, value 8}} Behaviors of `func intersection(Set<Set.Element>)` and `func subtracting(Set<Set.Element>)` were different between normal Swift class and NSObject subclasses. I had thought they should be the same. It seemed that Set<NSObject> relied on addresses of NSObject instances instead of their hashValues. That made the Set useless. Swift version: 3.1 (swiftlang-802.0.48 clang-802.0.48) Xcode 8.3 (8E162) Zhaoxin _______________________________________________ swift-users mailing list swift-users@swift.org<mailto:swift-users@swift.org> https://lists.swift.org/mailman/listinfo/swift-users
_______________________________________________ swift-users mailing list swift-users@swift.org https://lists.swift.org/mailman/listinfo/swift-users