Протокол Swift @ obj c не может использоваться в качестве типа, соответствующего протоколу «Equatable», поскольку «Equatable» соответствует требованиям c - PullRequest
0 голосов
/ 23 февраля 2020

В настоящее время я пишу повторно используемый компонент пользовательского интерфейса в Swift, который предполагается использовать из обоих миров 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 есть требования stati c. Itemable определяется следующим образом:

@objc protocol Itemable { //methods and properties }

Кроме того, не знаете, как сделать его эквивалентным. Видимо, следующее помогает, но не уверен почему-

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

Мне кажется, что это может потребовать стирания типа, но не уверен, как это сделать go.

Вот сокращенное версия протокола, показывающая все различные типы методов и свойств, присутствующих - на самом деле не имеет ничего типа c или связанного типа.

 @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 голосов
/ 23 февраля 2020

Вы не можете заставить тип @objc соответствовать Equatable. У Equatable есть требование к Себе. Протоколы Objective- C не могут express самостоятельного требования.

Ваша функция == может использоваться, но она не приводит к тому, что тип соответствует Equatable. Это просто означает, что вы можете оценить item == item. Вы не можете, однако, вызвать items.contain(item), так как Itemable не соответствует Equatable. То, что вы можете сделать, это вызвать items.contains{$0 == item}, поскольку для этого просто необходима функция ==, а не Equatable. И, конечно, вы можете реализовать пользовательский метод .contains для [Itemable], если хотите. Но это все равно не будет Equatable.

Для вашего примера я считаю, что вы хотите полностью избавиться от == и использовать это:

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

Если вы сделаете это a конечно, вы можете добавить расширение на [Itemable] (не проверено):

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

Тогда ваш оригинальный код будет в порядке.

Несколько не связано с вашим вопросом: возможно, это упрощенный код, но будьте очень осторожны с такого рода реализацией ==. Во-первых, == всегда должен проверять все видимые свойства. Если, например, aProperty является просто идентификатором, то это опасный способ реализовать ==. Когда две вещи равны (как в Obj C, так и в Swift), ожидается, что они взаимозаменяемы во всех контекстах. Если вы когда-нибудь заботитесь о том, какой у вас есть, они на самом деле не «равны».

Кроме того, когда две вещи равны, они должны иметь одинаковое значение ha sh (и если они равны, они должен иметь тот же га sh).

См. Документацию по В соответствии с Equatable Protocol для правил. Хотя == технически не подразумевает Equatable, использование его сбивает с толку, если вы не имеете в виду Equatable.

...