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



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

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

其中CCD_ 3是CCD_ 4(协议(类型的阵列。

然而,我得到了一个错误,说我不能把它用作符合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 })
}
} 

不能使@objc类型符合Equatable。Equatable有自我要求。Objective-C协议不能表达Self要求。

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

对于您的示例,我相信您希望完全摆脱==,并使用以下内容:

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中(,它们在所有上下文中都可以互换。如果你在乎你有哪一个,他们并不是真正的"平等">

此外,当两个事物相等时,它们应该具有相同的哈希(如果它们是可等式的,则它们必须具有相同的散列(。

有关规则,请参阅关于遵守赤道协议的文档。虽然==在技术上并不意味着Equatable,但如果你不是指Equatable的话,那么使用它是令人困惑的。

最新更新