ios – Equatable实现似乎不适用于泛型

前端之家收集整理的这篇文章主要介绍了ios – Equatable实现似乎不适用于泛型前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我仍然在与 Swift仿制药作斗争.今天我发现我的Equatable协议实现不起作用,如果它是从泛型类调用的.

我的模特课:

  1. func ==(lhs: Tracking,rhs: Tracking) -> Bool {
  2. // This method never executes if called from BaseCache
  3. return lhs.id == rhs.id
  4. }
  5.  
  6. class Tracking: NSObject,Equatable,Printable {
  7. var id: String?
  8. .....
  9. }

类,使用泛型类型:

  1. class BaseCache<T: NSObject where T: Equatable,T: Printable> {
  2.  
  3. .....
  4.  
  5. func removeEntities(entities: [T]) {
  6. var indexesToRemove = [Int]()
  7. for i in 0...allEntities.count - 1 {
  8. let item = allEntities[i]
  9. for entity in entities {
  10. println("equal: \(entity == item)")
  11. // FOR SOME REASONS THE STATEMENT BELOW IS ALWAYS FALSE
  12. if entity == item {
  13. indexesToRemove.append(i)
  14. break
  15. }
  16. }
  17. }
  18. for index in indexesToRemove {
  19. allEntities.removeAtIndex(index)
  20. }
  21. didRemoveEntities()
  22. }
  23. }

它的子类:

  1. class TrackingCache<T: Tracking>: BaseCache<Tracking> {
  2. }

当我调用TrackingCache实例的removeEntities方法时,我总是在输出中得到相等的:false,即使id是相同的.

但是,如果我直接将方法移动到TrackingCache类,它似乎工作正常!

任何想法为什么会发生这种情况以及如何解决这个问题?

解决方法

注意:因为==不是成员函数,所以默认情况下它不会给你动态调度,包括你在通用占位符旁边使用它.

请考虑以下代码

  1. class C: NSObject,Equatable {
  2. let id: Int
  3. init(_ id: Int) { self.id = id }
  4. }
  5.  
  6. // define equality as IDs are equal
  7. func ==(lhs: C,rhs: C) -> Bool {
  8. return lhs.id == rhs.id
  9. }
  10.  
  11. // create two objects with the same ID
  12. let c1 = C(1)
  13. let c2 = C(1)
  14.  
  15. // true,as expected
  16. c1 == c2

好的,现在创建两个NSObject类型的变量,并为它们分配相同的值:

  1. let o1: NSObject = c1
  2. let o2: NSObject = c2
  3.  
  4. // this will be false
  5. 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更具体.

这是一个更简单的例子,只是通用函数

  1. func f<T: NSObject>(lhs: T,rhs: T) -> Bool {
  2. return lhs == rhs
  3. }
  4.  
  5. func g<T: C>(lhs: T,rhs: T) -> Bool {
  6. return lhs == rhs
  7. }
  8.  
  9. f(c1,c2) // false
  10. g(c1,c2) // true

如果要解决此问题,可以覆盖isEqual:

  1. class C: NSObject,Equatable {
  2. ...
  3. override func isEqual(object: AnyObject?) -> Bool {
  4. return (object as? C)?.id == id
  5. }
  6. }
  7.  
  8. // this is now true:
  9. o1 == o2
  10. // as is this:
  11. f(c1,c2)

这种技术(具有==调用动态调度的类方法)也是一种为非NSObject类实现此行为的方法.当然,结构没有这个问题,因为它们不支持继承 – 结构得分为1!

猜你在找的iOS相关文章