ios - 使用泛型时的 EXC_BAD_ACCESS

标签 ios generics swift exc-bad-access

我正在尝试使用 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 执行此操作,但我要添加一些警告,这意味着您可能不想使用这种方法:

  1. 您正在检查一个属性 slug,以测试是否相等。 Swift 中的相等性意味着可替换性——即如果两个元素通过 == 相等,它们应该完全等价,并且您应该能够在没有人注意到的情况下用一个替换另一个。如果您的飞船的属性可能会有所不同,即使它们的 slug 属性相同,情况也不会如此。如果您使用依赖于此可替换性属性的库函数,如 containssort,这可能会导致一些严重的错误。如果您使用的是类,那么您可能会发现恒等运算符 (===) 是用于实现相等运算符的好东西。

  2. 使用 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/

相关文章:

ios - SWIFT:按钮不会在点击时消失

java - 跟踪前泛型 Java 中集合中的内容?

swift - 具有关联类型和工厂模式的协议(protocol)?

ios - 如何复制self.title?

iphone - NSNotificationCenter 关于 ViewWillAppear 和 ViewWillDisapper

ios - 如何仅在iOS中验证长度并将文本字段限制为数字,字母数字和字母字符

java - 在 Java 源代码中使用泛型的力量

ios - 如何在其他类中使用导入的HealthKit样本

json - 尝试使用 didSelectRowAtIndexPath 更新标签

c# - 统一: Apple Game Center iOS7 registers the scores for only 30 minutes in the leaderboard