Использование перечисления Swift для просмотра номеров тегов без rawValue

У меня есть целочисленное перечисление, которое я хотел бы использовать для viewWithTag(_:) число, но это дает мне ошибку "Невозможно преобразовать значение типа 'viewTags' в ожидаемый тип аргумента 'Int'", хотя и перечисление, и номер тега необходимы в viewWithTag(_:) является Int,

Это довольно просто, и я могу заставить его работать, если я использую rawValue собственность, но это более грязно и громоздко, чем мне бы хотелось.

enum viewTags: Int {
    case rotateMirroredBtn
    case iPhone6SP_7P_8P
    case iPhoneX_Xs
    case iPhoneXs_Max
    case iPhone_Xr
    case unknown
}

// error on if statement "Cannot convert value of type 'viewTags' to expected argument type 'Int'"
if let tmpButton = self.view.viewWithTag(viewTags.rotateMirroredBtn) as? UIButton { 
    tmpButton.removeFromSuperview()
}

2 ответа

Решение

Вы можете легко добавить расширение на UIView сделать преобразование для вас. Вам просто нужно использовать универсальный параметр, чтобы ограничить аргумент тем, что вы можете получить Int от.

extension UIView
{
    /**
     Returns the view’s nearest descendant (including itself) whose `tag`
     matches the raw value of the given value, or `nil` if no subview
     has that tag.
     - parameter tag: A value that can be converted to an `Int`.
     */
    func firstView <Tag : RawRepresentable> (taggedBy tag: Tag) -> UIView?
        where Tag.RawValue == Int
    {
        let intValue = tag.rawValue
        return self.viewWithTag(intValue)
    }
}

Ограничение T : RawRepresentable where T.RawValue == Int может быть выполнено вашим IntПеречисление

Непатентованная форма тоже проста: func firstView(taggedBy viewTag: ViewTag) -> UIView?

Кроме того, вы также можете добавить метод для применения необработанного значения "составного" значения к представлению:

func applyTag <Tag : RawRepresentable> (_ tag: Tag)
    where Tag.RawValue == Int
{
    self.tag = tag.rawValue
}

(К сожалению, нет возможности записать это как свойство, например, var composedTag: Tag where Tag : RawRepresentable, Tag.RawValue == Int потому что вычисляемое свойство не может создать свой собственный общий контекст, как метод.)

Я, как и оригинальный плакат, не предпочитаю использовать футляр rawValueв коде, поэтому я добавил свойства вычисляемого типа в свои перечисления. Я использую Xcode v11.3.1 и Swift v5.1.3.

Например, многие из написанных мною модульных тестов использовали "магические" значения для создания IndexPath для табличных представлений с таким кодом:

let activeIndexPath = IndexPath(row: 0, section: 0)
let finishedIndexPath = IndexPath(row: 0, section: 1)

Я не хотел этого делать, хотя это улучшение по сравнению с "магическими" значениями:

let activeIndexPath = IndexPath(row: 0, section: TableViewSection.active.rawValue)
let finishedIndexPath = IndexPath(row: 0, section: TableViewSection.finished.rawValue)

Меня больше всего беспокоит тестируемая часть табличного представления, поэтому я придумал это перечисление, которое использует свойства вычисляемого типа для получения Int rawValues:

enum TableViewSection: Int {
    case active
    case finished

    static var sectionActive: Int { return Self.active.rawValue }
    static var sectionFinished: Int { return Self.finished.rawValue }
}

Теперь я могу создать IndexPath следующим образом:

let indexPathActive = IndexPath(row: 0, section: TableViewSection.sectionActive)

Обратной стороной является то, что вам нужно вычисляемое свойство с одинаковым именем для каждого случая, но конечный результат более нагляден на сайте вызова (хотя я предполагаю, что код, который использует rawValue, также является описательным), и теперь мне не нужно запомните, какое значение Int использовать для каждого конкретного раздела табличного представления, и мне больше не нужно использовать "магические" значения, что, как мы все знаем, плохо.

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

Единственное, что вы упускаете rawValue, Просто замени viewTags.rotateMirroredBtn с viewTags.rotateMirroredBtn.rawValue как это:

if let tmpButton = self.view.viewWithTag(viewTags.rotateMirroredBtn.rawValue) as? UIButton { 
    tmpButton.removeFromSuperview()
}
Другие вопросы по тегам