我的模特课:
- func ==(lhs: Tracking,rhs: Tracking) -> Bool {
- // This method never executes if called from BaseCache
- return lhs.id == rhs.id
- }
- class Tracking: NSObject,Equatable,Printable {
- var id: String?
- .....
- }
类,使用泛型类型:
- class BaseCache<T: NSObject where T: Equatable,T: Printable> {
- .....
- func removeEntities(entities: [T]) {
- var indexesToRemove = [Int]()
- for i in 0...allEntities.count - 1 {
- let item = allEntities[i]
- for entity in entities {
- println("equal: \(entity == item)")
- // FOR SOME REASONS THE STATEMENT BELOW IS ALWAYS FALSE
- if entity == item {
- indexesToRemove.append(i)
- break
- }
- }
- }
- for index in indexesToRemove {
- allEntities.removeAtIndex(index)
- }
- didRemoveEntities()
- }
- }
它的子类:
- class TrackingCache<T: Tracking>: BaseCache<Tracking> {
- }
当我调用TrackingCache实例的removeEntities方法时,我总是在输出中得到相等的:false,即使id是相同的.
但是,如果我直接将方法移动到TrackingCache类,它似乎工作正常!
任何想法为什么会发生这种情况以及如何解决这个问题?
解决方法
请考虑以下代码:
- class C: NSObject,Equatable {
- let id: Int
- init(_ id: Int) { self.id = id }
- }
- // define equality as IDs are equal
- func ==(lhs: C,rhs: C) -> Bool {
- return lhs.id == rhs.id
- }
- // create two objects with the same ID
- let c1 = C(1)
- let c2 = C(1)
- // true,as expected
- c1 == c2
好的,现在创建两个NSObject类型的变量,并为它们分配相同的值:
- let o1: NSObject = c1
- let o2: NSObject = c2
- // this will be false
- o1 == o2
为什么?因为你正在调用函数func ==(lhs:NSObject,rhs:NSObject) – > Bool,不是func ==(lhs:C,rhs:C) – >布尔.根据o1和o2所指的内容,在运行时不会动态确定要选择哪个重载函数.它是由Swift在编译时根据o1和o2的类型确定的,在这种情况下是oSObject.
NSObject ==的实现与你的equals不同 – 它调用lhs.isEqual(rhs),如果不覆盖检查引用相等(即两个引用指向同一个对象),它会回退.他们不是,所以他们不平等.
为什么在BaseCache中会发生这种情况,而在TrackingCache中却没有?因为BaseCache被定义为仅限制为NSObject,所以T只具有NSObject的功能 – 类似于将c1分配给NSObject类型的变量时,将调用==的NSObject版本.
另一方面,TrackingCache保证T至少是一个Tracking对象,因此使用了跟踪的==版本. Swift会选择所有可能重载的“特定” – 跟踪比它的基类NSObject更具体.
这是一个更简单的例子,只是通用函数:
- func f<T: NSObject>(lhs: T,rhs: T) -> Bool {
- return lhs == rhs
- }
- func g<T: C>(lhs: T,rhs: T) -> Bool {
- return lhs == rhs
- }
- f(c1,c2) // false
- g(c1,c2) // true
如果要解决此问题,可以覆盖isEqual:
- class C: NSObject,Equatable {
- ...
- override func isEqual(object: AnyObject?) -> Bool {
- return (object as? C)?.id == id
- }
- }
- // this is now true:
- o1 == o2
- // as is this:
- f(c1,c2)
这种技术(具有==调用动态调度的类方法)也是一种为非NSObject类实现此行为的方法.当然,结构没有这个问题,因为它们不支持继承 – 结构得分为1!