swift - NSObject उपवर्ग में स्विफ्ट: हैश बनाम हैशवैल, इसक्वल बनाम==
cocoa (2)
Hashable
लागू करें, जिसके लिए आपको अपने प्रकार के लिए
==
ऑपरेटर को भी लागू करना होगा।
ये स्विफ्ट मानक लाइब्रेरी में बहुत उपयोगी सामान के लिए उपयोग किए जाते हैं जैसे
indexOf
फ़ंक्शन जो केवल एक प्रकार के संग्रह पर काम करता है जो
Equatable
, या
Set<T>
प्रकार को लागू करता है जो केवल
Equatable
को लागू करने वाले प्रकारों के साथ काम करता है।
जब स्विफ्ट में NSObject को उपवर्गित कर रहा है, तो क्या आपको हैश को ओवरराइड करना चाहिए या हसबल को लागू करना चाहिए? इसके अलावा, क्या आप को अलग करना चाहिए: या लागू करना ==?
NSObject
पहले से ही
Hashable
प्रोटोकॉल के अनुरूप है:
extension NSObject : Equatable, Hashable {
/// The hash value.
///
/// **Axiom:** `x == y` implies `x.hashValue == y.hashValue`
///
/// - Note: the hash value is not guaranteed to be stable across
/// different invocations of the same program. Do not persist the
/// hash value across program runs.
public var hashValue: Int { get }
}
public func ==(lhs: NSObject, rhs: NSObject) -> Bool
मुझे कोई आधिकारिक संदर्भ नहीं मिला, लेकिन ऐसा लगता है कि
hashValue
ने
NSObjectProtocol
से
hash
विधि को कॉल किया, और
==
isEqual:
पद्धति (उसी प्रोटोकॉल से) को कॉल करता है।
जवाब के अंत में अपडेट देखें!
NSObject
उपवर्गों के लिए, सही तरीका
hash
और
isEqual:
को ओवरराइड करने के लिए लगता है
isEqual:
और यहां एक प्रयोग है जो यह दर्शाता है कि:
1.
hashValue
और
==
ओवरराइड करें
class ClassA : NSObject {
let value : Int
init(value : Int) {
self.value = value
super.init()
}
override var hashValue : Int {
return value
}
}
func ==(lhs: ClassA, rhs: ClassA) -> Bool {
return lhs.value == rhs.value
}
अब कक्षा के दो अलग-अलग उदाहरण बनाएं, जिन्हें "समान" माना जाता है और उन्हें एक सेट में रखा जाता है:
let a1 = ClassA(value: 13)
let a2 = ClassA(value: 13)
let nsSetA = NSSet(objects: a1, a2)
let swSetA = Set([a1, a2])
print(nsSetA.count) // 2
print(swSetA.count) // 2
जैसा कि आप देख सकते हैं,
NSSet
और
Set
दोनों वस्तुओं को अलग-अलग मानते हैं।
यह वांछित परिणाम नहीं है।
Arrays के अप्रत्याशित परिणाम भी हैं:
let nsArrayA = NSArray(object: a1)
let swArrayA = [a1]
print(nsArrayA.indexOfObject(a2)) // 9223372036854775807 == NSNotFound
print(swArrayA.indexOf(a2)) // nil
ब्रेकपॉइंट सेट करना या डीबग आउटपुट जोड़ना यह बताता है कि ओवरराइड
==
ऑपरेटर को कभी नहीं कहा जाता है।
मुझे नहीं पता कि यह एक बग या इच्छित व्यवहार है।
2. ओवरराइड
hash
और
isEqual:
class ClassB : NSObject {
let value : Int
init(value : Int) {
self.value = value
super.init()
}
override var hash : Int {
return value
}
override func isEqual(object: AnyObject?) -> Bool {
if let other = object as? ClassB {
return self.value == other.value
} else {
return false
}
}
}
स्विफ्ट 3
के लिए
isEqual:
की परिभाषा
isEqual:
बदल गई
override func isEqual(_ object: Any?) -> Bool { ... }
अब सभी परिणाम अपेक्षित हैं:
let b1 = ClassB(value: 13)
let b2 = ClassB(value: 13)
let nsSetB = NSSet(objects: b1, b2)
let swSetB = Set([b1, b2])
print(swSetB.count) // 1
print(nsSetB.count) // 1
let nsArrayB = NSArray(object: b1)
let swArrayB = [b1]
print(nsArrayB.indexOfObject(b2)) // 0
print(swArrayB.indexOf(b2)) // Optional(0)
अद्यतन: व्यवहार को "कोको और उद्देश्य-सी" संदर्भ के साथ स्विफ्ट का उपयोग करते हुए ऑब्जेक्टिव-सी एपीआई के साथ बातचीत में प्रलेखित किया गया है:
NSObject वर्ग केवल एक पहचान तुलना करता है, इसलिए आपको अपनी खुद की isEqual: NSObject कक्षा से प्राप्त होने वाली कक्षाओं में विधि लागू करनी चाहिए।
अपने वर्ग के लिए समानता को लागू करने के भाग के रूप में, वस्तु तुलना में नियमों के अनुसार हैश संपत्ति को लागू करना सुनिश्चित करें।