[swift-users] Set with element of NSObject subclasses didn't work as expected
Zhao Xin
owenzx at gmail.com
Wed Mar 29 04:36:58 CDT 2017
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 <saagar at 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 at swift.org<mailto:swift-users at 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 <owenzx at gmail.com<mailto:owenzx at 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 at swift.org<mailto:swift-users at swift.org>
https://lists.swift.org/mailman/listinfo/swift-users
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-users/attachments/20170329/73903022/attachment.html>
More information about the swift-users
mailing list