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

问题描述 投票:0回答:1

我目前正在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
}

在我看来,可能需要擦除类型,但不确定如何执行此操作。

objective-c swift generics protocols type-erasure
1个回答
0
投票

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

您的==函数可用,但不会导致类型符合Equatable。这仅表示您可以评估item == item。但是,由于Itemable不符合Equatable,因此无法调用items.contain(item)。您可以执行的操作是调用items.contains{$0 == item},因为这只需要==功能,而不是等值的。当然,如果需要,可以为.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? {
        index(where: { $0.aProperty == item.aProperty })
    }
}

那么您的原始代码就可以了。

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

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

请参阅Conforming to the Equatable Protocol中的文档以获取规则。尽管从技术上讲==并不表示可等于,但如果您不等于可等于,则使用它会令人困惑。

© www.soinside.com 2019 - 2024. All rights reserved.