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

我仍然在与 Swift仿制药作斗争.今天我发现我的Equatable协议实现不起作用,如果它是从泛型类调用的.

我的模特课:

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!

相关文章

UITabBarController 是 iOS 中用于管理和显示选项卡界面的一...
UITableView的重用机制避免了频繁创建和销毁单元格的开销,使...
Objective-C中,类的实例变量(instance variables)和属性(...
从内存管理的角度来看,block可以作为方法的传入参数是因为b...
WKWebView 是 iOS 开发中用于显示网页内容的组件,它是在 iO...
OC中常用的多线程编程技术: 1. NSThread NSThread是Objecti...