我正在尝试使用 Swift 中的泛型为我的实体实现缓存。这是我的代码:
class BaseCache<T>: NSObject {
var allEntities = [T]()
// MARK: - Append
func appendEntities(newEntities: [T]) {
for entity in newEntities {
// Check if allEntities array already contains an entity
var contains = false
for item in allEntities {
// EXC_BAD_ACCESS in isEqual method (see below)
if isEqual(entity, rightEntity: item) {
contains = true
break
}
}
if !contains {
allEntities.append(entity)
}
}
}
func isEqual(leftEntity: T, rightEntity: T) -> Bool {
return false
}
}
下面是BaseCache的具体实现:
class CourierCache<T: AftershipCourier>: BaseCache<T> {
override func isEqual(leftEntity: T, rightEntity: T) -> Bool {
println("\(leftEntity)") // EXC_BAD_ACCESS here
println("\(rightEntity)")
return rightEntity.slug == leftEntity.slug
}
}
有什么解决办法吗?谢谢!
PS:请注意 this question与我的问题无关
最佳答案
在我看来,您发现了一个 Swift 错误。这是我能得到的最简单的方法:
class C { }
class Base<T> {
func callCrash(t: T) {
crash(t)
}
func crash(t: T) { }
}
class Sub<T: C>: Base<T> {
override func crash(t: T) {
println(t) // EXC_BAD_ACCESS here
}
}
let sub = Sub<C>()
sub.callCrash(C())
但是,如果将检测相等性的能力放入协议(protocol)中,然后要求对象而不是缓存来检查是否相等,您可能会得到更好的服务。
@rakeshbs 的回答显示了如何使用 Equatable
执行此操作,但我要添加一些警告,这意味着您可能不想使用这种方法:
您正在检查一个属性
slug
,以测试是否相等。 Swift 中的相等性意味着可替换性——即如果两个元素通过==
相等,它们应该完全等价,并且您应该能够在没有人注意到的情况下用一个替换另一个。如果您的飞船的属性可能会有所不同,即使它们的slug
属性相同,情况也不会如此。如果您使用依赖于此可替换性属性的库函数,如contains
或sort
,这可能会导致一些严重的错误。如果您使用的是类,那么您可能会发现恒等运算符 (===
) 是用于实现相等运算符的好东西。使用 equatable 和
<==
运算符和泛型意味着您的比较函数将被静态绑定(bind),因为运算符不是成员函数。这意味着如果您在缓存中保存层次结构中的不同对象,您将不会在==
运算符上获得动态调度。也就是说,如果您有一个AftershipCourier
缓存并将FastAftershipCourier
类放入其中,您会发现==
用于AftershipCourier
在它们之间运行,而不是比较FastAftershipCourier
的自定义==
。因此,如果您需要动态行为,请确保让==
在传入的参数上调用一个方法,该方法可以被子类覆盖,而不是直接比较属性。
要解决这两个问题,请使用您自己设计的带有比较功能的协议(protocol),让 express 类实现它,然后在您的缓存代码中调用它。
附言针对 allEntities 检查实体的 for 循环可以写成 let alreadyContained = contains(allEntities) { entity.comparingFuncYouDecideOn($0) }
关于ios - 使用泛型时的 EXC_BAD_ACCESS,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27762967/