Вложенные перечисления, соответствующие протоколу Equatable, выдают ошибку - PullRequest
0 голосов
/ 06 марта 2019

У меня есть протокол с именем TableViewItem. Этот протокол обеспечивает, что соответствующие объекты реализуют свойство type, в качестве типа которого используется протокол TableViewCellIdentifiable. TableViewCellIdentifiable используется для группировки трех вложенных перечислений, как показано ниже:

internal protocol TableViewCellIdentifiable: Equatable { }

internal enum TableViewCellType {
    internal enum PortfolioSelection: String, TableViewCellIdentifiable {
        case portfolio = "portfolioTableViewCell"
        case enterPortfolioDetails = "enterPortfolioDetailsTableViewCell"
        case addPortfolio = "actionTableViewCell"
    }

    internal enum EditPortfolio: String, TableViewCellIdentifiable {
        case editPortfolioName = "editPortfolioNameTableViewCell"
        case deletePortfolio = "deletePortfolioTableViewCell"
    }

    internal enum Portfolio: String, TableViewCellIdentifiable {   
        case portfolioAsset = "portfolioAssetTableViewCell"
        case addAsset = "actionTableViewCell"
    }
}

Вот пример того, как это используется:

internal final class EditPortfolioNameTableViewItem: TableViewItem {

    // MARK: - Internal Properties

    internal let type: TableViewCellIdentifiable = TableViewCellType.EditPortfolio.editPortfolioName
    internal let viewModel: TableViewCellModel

    // MARK: - Initialization

    internal init(viewModel: EditPortfolioNameTableViewCellModel) {
        self.viewModel = viewModel
    }
}

К сожалению, в строке, где я объявляю свойство type, я получаю следующую ошибку:

Протокол 'TableViewCellIdentifiable' может использоваться только в качестве общего ограничения, поскольку он имеет требования к Self или связанный тип

Я прочитал другие вопросы / ответы от других, кто сталкивался с этой ошибкой, но я не могу полностью понять, почему эта конкретная реализация проблематична, и каково будет решение. Я знаю, что Equatable является источником проблемы, однако это крайне важно для функциональности, поскольку перечисления служат двум целям:

  1. Чтобы обеспечить идентификаторы повторного использования для ячеек табличного представления (необработанные значения).
  2. Чтобы позволить сравнивать типы - т.е.:

    self.tableViewItems.contains(where: { $0.type == item.type })
    

Любые предложения будут высоко оценены, даже если это будет означать альтернативный подход.

Ответы [ 2 ]

2 голосов
/ 06 марта 2019

В вашей голове должен компилироваться следующий код?

var x : Equatable

Не должно.Почему?

Потому что, если у вас было:

var x : Equatable 
var y : Equatable

, то компилятор не может гарантировать, что x & y того же типа.x может быть "John", потому что "John" / Strings являются Equatable ... все время y может быть 10, потому что 10 / целые числа равны.

и компилятор подозревает, чтонесколькими строками ниже вы можете захотеть сделать

if x == y { print ("equal" } 

, которые он не может обработать.Так что это просто мешает вам когда-либо делать это в начале.


Следующая строка вашего кода вызовет ту же ошибку по вышеуказанной причине.

internal let type: TableViewCellIdentifiable = TableViewCellType.EditPortfolio.editPortfolioName
1 голос
/ 06 марта 2019

Как объясняется в ответе Хани, TableViewCellIdentifiable не предоставляет достаточно информации о типе для работы с компилятором.Возможно, вы могли бы применить другой подход, который немного изменяет структуру (и потенциально является избыточным), но обеспечивает требуемую функциональность:

internal protocol ValueAssociated { }

internal extension ValueAssociated {

    fileprivate var association: (label: String, value: Any?)? {
        get {
            let mirror = Mirror(reflecting: self)
            if let association = mirror.children.first, let label = association.label {
                return (label, association.value)
            }
            return nil
        }
    }
}

internal protocol CellIdentifiable {

    var rawValue: String { get }
}

internal enum CellType: Equatable, ValueAssociated {

    case portfolio(PortfolioIdentifier)
    case portfolioSelection(PortfolioSelectionIdentifier)
    case editPortfolio(EditPortfolioIdentifier)

    internal var identifier: String? {
        return (self.association?.value as? CellIdentifiable)?.rawValue
    }

    internal enum PortfolioIdentifier: String, Equatable, CellIdentifiable {

        case portfolioAsset = "portfolioAssetTableViewCell"
        case addAsset = "actionTableViewCell"
    }

    internal enum PortfolioSelectionIdentifier: String, Equatable, CellIdentifiable {

        case portfolio = "portfolioTableViewCell"
        case enterPortfolioDetails = "enterPortfolioDetailsTableViewCell"
        case addPortfolio = "actionTableViewCell"
    }

    internal enum EditPortfolioIdentifier: String, Equatable, CellIdentifiable {

        case editPortfolioName = "editPortfolioNameTableViewCell"
        case deletePortfolio = "deletePortfolioTableViewCell"
    }
}

Это можно использовать следующим образом:

internal let cellType: CellType = .portfolio(.portfolioAsset)
print(cellType.identifier!) // Prints "portfolioAssetTableViewCell"

Надеюсь, это поможет.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...