Swift @objc协议不能用作符合协议“ Equatable”的类型,因为“ Equatable”具有静态要求

时间:2020-02-23 08:02:26

标签: objective-c swift generics protocols type-erasure

我目前正在用Swift编写一个可重用的UI组件,应该从两个Obj-C / Swift世界中使用它(这是一个混合项目)。我定义了一个@objc协议,但没有任何关联的类型(因为@objc协议不允许使用这些类型)。在组件中的一种方法中,我需要将协议存储为一种类型,并且需要找到特定条目的索引,这与以下内容有些相似-

func select<T: Itemable>(_ item: T) {
    guard let itemIndex = items.index(of: item) else {
        return
    }
  //more stuf
}

其中itemsItemable(协议)类型的数组。

但是,我收到一个错误消息,说我不能将其用作符合Equatable的类型,因为equatable具有静态要求。 Itemable的定义如下-

@objc protocol Itemable { //methods and properties }

此外,不确定如何使其符合等值。显然,以下内容可以帮助但不确定原因-

func ==<T: <Itemable>>(lhs: T, rhs: T) -> Bool {
    return lhs.aProperty == rhs.aProperty
}

在我看来,这可能需要擦除类型,但不确定如何去做。

这是该协议的简化版本,显示了存在的所有不同类型的方法和属性-它实际上没有任何静态或关联类型。

 @objc protocol Itemable {
    typealias voidBlock = () -> Void
    var color: UIColor { get }
    var screenParameters: [String : String] { get }
    var screenView: String { get }
    var iconImage: UIImage? { get }
    @objc var accessibilityLabel: String? { get }
}

extension Array where Element: Itemable {
    func index(of element: Element) -> Int? {
        index(where: { $0.screenView == element.screenView })
    }
} 

1 个答案:

答案 0 :(得分:0)

您不能使@objc类型符合Equatable。平等的有自我要求。 Objective-C协议无法表达自我要求。

您的==函数是可用的,但不会导致类型符合Equatable。这只是意味着您可以评估item == item。但是,由于Itemable不符合Equatable,因此您不能调用items.contain(item)。您可以执行的操作是调用items.contains{$0 == item},因为这仅需要==函数,而不是Equatable函数。当然,如果需要,您可以为.contains实现自定义[Itemable]方法。但这仍然不是平等的。

例如,我相信您想完全摆脱==,并使用它:

guard let itemIndex = items.index(where: { $0.aProperty == item.aProperty }) else {

如果您经常这样做,当然可以在[Itemable]上添加扩展名(未经测试):

extension Array where Element: Itemable {
    func index(of element: Element) -> Int? {
        firstIndex(where: { $0.aProperty == element.aProperty })
    }
}

然后您的原始代码就可以了。

与您的问题无关的部分:这可能是简化的代码,但请注意==的这种实现。首先,==应该始终测试所有可见属性。例如,如果aProperty仅是ID,则这是实现==的危险方式。当两个条件相等时(在ObjC和Swift中),它们在所有上下文中都可以互换。如果您曾经关心拥有哪一个,那么它们并不是真正的“平等”。

另外,当两个事物相等时,它们应该具有相同的哈希值(如果它们是等值的,则它们必须具有相同的哈希值)。

有关规则,请参见Conforming to the Equatable Protocol上的文档。尽管==从技术上讲并不意味着可等于,但如果您不等于可等于,则使用它会令人困惑。