我目前正在用Swift编写一个可重用的UI组件,这个组件应该是从Obj/ Swift世界中使用的(这是一个混合项目)。我定义了一个没有任何关联类型的@objc协议(因为@objc协议不允许这些类型)。在组件中的一种方法中,我需要将协议存储为一种类型,并需要查找特定条目的索引,类似于以下内容-
func select<T: Itemable>(_ item: T) {
guard let itemIndex = items.index(of: item) else {
return
}
//more stuf
}其中items是Itemable (协议)类型的数组。
然而,我得到的错误说,我不能使用它作为一种类型符合等价物,因为等式有静态的要求。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 })
}
} 发布于 2020-02-23 16:54:48
您不能使@objc类型符合相等。赤道有自己的要求。目标-C协议不能表达自己的需求。
您的==函数是可用的,但它不会导致该类型符合等价类。这只意味着您可以评估item == item。但是,您不能调用items.contain(item),因为Itemable不符合等价性。您可以做的是调用items.contains{$0 == item},因为这只需要==函数,而不是等价的。当然,如果需要的话,可以为[Itemable]实现一个自定义的[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中),它们在所有上下文中都是可互换的。如果你曾经关心过你拥有哪一个,它们并不是真正的“平等”。
另外,当两个条件相等时,它们应该有相同的散列(如果它们是相等的,它们必须具有相同的散列)。
有关规则,请参阅符合“平等议定书”上的文档。虽然==在技术上并不意味着等同,但如果您的意思不是可等价物,那么使用它是令人困惑的。
https://stackoverflow.com/questions/60360248
复制相似问题