我的模特课:
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!