在Swift中将NSObject子类化时,您应该重写哈希还是实现Hashable?另外,您应该重写isEqual:还是实现==?
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
调用了hash
方法NSObjectProtocol
,并从相同的协议中==
调用了该
isEqual:
方法。 请参阅答案末尾的更新!
对于NSObject
子类,正确的方法似乎是重写hash
和isEqual:
,这是一个实验,证明了这一点:
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
治疗的对象不同。这不是期望的结果。数组也有意外的结果:
let nsArrayA = NSArray(object: a1)
let swArrayA = [a1]
print(nsArrayA.indexOfObject(a2)) // 9223372036854775807 == NSNotFound
print(swArrayA.indexOf(a2)) // nil
设置断点或添加调试输出表明,==
永远不会调用覆盖的 运算符。我不知道这是错误还是预期的行为。
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
}
}
}
对于 Swift 3, 定义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)
更新: 该行为现在在 “与Swift与Cocoa和Objective-C一起使用”参考中与Objective-C
API交互中进行
了记录 :
NSObject类仅执行身份比较,因此您应该在从NSObject类派生的类中实现自己的isEqual:方法。
作为为类实现相等性的一部分,请确保根据对象比较中的规则实现hash属性。
问题内容: 我测试了一些用Swift编写的isa,发现它仅在NSObject是超类(直接或更高级)或使用’@objc’装饰时才有效。否则,它将遵循静态和vtable- dispatch样式,例如C ++。 定义没有Cocoa / NSObject基类的Swift类是否正常?如果我担心的话,这意味着要放弃Objective- C的大部分活力,例如方法拦截和运行时自省。 动态运行时行为位于属性观察器,
问题内容: 我已经读过类似这样的文章,其中介绍了在Swift中进行子类化或仅具有其本机基础而不进行子类化的区别。但是它们都有些过时,我对此主题尚不清楚。 什么时候应该继承?子类化与不子类化之间的实际区别是什么?Swift中的建议是什么? 问题答案: 苹果公司有关NSObject的文档介绍如下: NSObject是大多数Objective-C类层次结构的根类。通过NSObject,对象继承了运行时系
问题内容: 我想子类化并显示类似视图的登录名。我已经在Objective- C中创建了它,但是现在我想将其移植到Swift。我不使用情节提要,所以我用代码创建了所有UI。 但是第一个问题是我必须执行。我给了它一个默认的实现,因为它不会被调用。现在,当我运行程序时,它崩溃了,因为我也必须实现。现在我得到了: 我的问题是我应该在哪里创建文本字段等…,如果我从不实现框架和编码器,该如何“隐藏”呢? 问题
但我想重写此行为,以便打印到控制台: 是否有方法清理此输出?我看过协议: 我认为会自动“看到”这一点,但情况似乎并非如此:
问题内容: 在Objective C中很简单:只需更新main.m文件并更改UIApplicationMain()参数即可 但是由于该指南指出,因此没有main.m文件 “在全局范围内编写的代码被用作程序的入口点,因此您不需要主要功能。” 那么,如何快速将UIApplication子类化?有什么建议吗? 问题答案: 注意: 如果您正在寻找以前的语法,请在2019年6月对XCode 10.1和Swi
NSObject+MethodCallDependingType 是 Objective-C 类,根据特定的类型来指定方法。