我目前正在用Swift编写一个可重用的UI组件,应该从两个Obj-C / Swift世界中使用它(这是一个混合项目)。我定义了一个@objc
协议,但没有任何关联的类型(因为@objc
协议不允许使用这些类型)。在组件中的一种方法中,我需要将协议存储为一种类型,并且需要找到特定条目的索引,这与以下内容有些相似-
func select<T: Itemable>(_ item: T) {
guard let itemIndex = items.index(of: item) else {
return
}
//more stuf
}
其中items
是Itemable
(协议)类型的数组。
但是,我收到一个错误消息,说我不能将其用作符合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 })
}
}
答案 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上的文档。尽管==
从技术上讲并不意味着可等于,但如果您不等于可等于,则使用它会令人困惑。