Переопределение или расширение UIColor для поддержки определенных протоколов - PullRequest
1 голос
/ 14 января 2020

Я пытаюсь создать подкласс или расширить UIColor для поддержки нескольких протоколов.

Допустим, мой протокол выглядит следующим образом:

public protocol MyProtocol {
    init(myValue: Any) throws
}

По какой-то причине я не могу реализовать его, и я не знаю почему.

Это работает для всех других классов:

class MyTestClass:SomeOtherClass, MyProtocol{
    required init(myValue: Any) throws{
        super.init(someOtherClassInitializer:Any)
    }
}

Нет проблем. Но если я пытаюсь сделать это с помощью UIColor, я получаю ошибки.

class MyColor:UIColor, MyProtocol{

    required init(myValue: Any) throws {
        super.init(red: 0, green: 0, blue: 0, alpha: 1)
    }
}

Прежде всего, он жалуется на required:Coder -init. Хорошо, предоставьте это. fatalError в порядке. Затем он жалуется на другой иници. В нем говорится, что

'обязательный' инициализатор 'init (_colorLiteralRed: green: blue: alpha :)' должен быть предоставлен подклассом 'UIColor'

Weird flex, но Хорошо. Давайте добавим это тоже. Я нажимаю «Исправить», и он добавляет эту заглушку:

@nonobjc required convenience init(_colorLiteralRed red: Float, green: Float, blue: Float, alpha: Float) {
    fatalError("init(_colorLiteralRed:green:blue:alpha:) has not been implemented")
}

Затем он дает мне две ошибки, одну идентичную той, на которую я только что нажал «Исправить» (которая добавляет другую идентичную инициализацию, и снова и еще раз), и другой, который говорит:

Переопределение non-@objc объявлений из расширений не поддерживается

Я не в расширении, но я предполагаю, что это удобный инициализатор возможно? Но тогда почему я должен реализовать - а также невозможно реализовать ?


Я знаю, «вы не должны подкласс UIColor», но я думаю, что я должен если я хочу, чтобы это сработало. Это странный запрос, поэтому некоторая справочная информация; Я использую библиотеку Apollo для выполнения сетевых задач GraphQL, которая использует скрипт для преобразования ожидаемого ответа в строго типизированные объекты swift, чтобы я мог использовать их в коде без десериализации их вручную. Он работает отлично.

Большинство значений являются стандартными и примитивными типами, такими как String, Int et c., Но иногда сервер пытается отправить мне объект класса, чуждого Swift, и по умолчанию они будут String. Что совершенно нормально. Но я хочу больше фантазии. Пример; значение «2020-01-14T10: 00: 00» может быть возвращено как класс с именем DateTime с сервера, но поскольку «DateTime» не существует ни в моем проекте, ни в Swift, автоматически созданные классы будут содержать их как String -значение, и мне придется рассматривать его как строку.

Поскольку я хочу использовать эти автоматически сгенерированные классы вплоть до представления, это означает, что я должен преобразовать его из Строка для даты везде, где она используется. Другой вариант - создать свои собственные версии всех классов и преобразовать все иностранные классы в свои собственные, например, String-> Date, что скучно. Я хочу, чтобы это делалось автоматически для меня.

Хорошо, что Apollo позволяет мне создавать свои собственные скаляры. Так что с этим примером «DateTime -> Date» я могу просто сказать

typealias DateTime = Date
extension DateTime, JSONDecodable, JSONEncodable{ ... }

Это позволяет Аполлону знать, что есть соответствующий класс, в который могут быть преобразованы объекты класса «DateTime». И протоколы JSONDecodable и JSONEncodable рассказывают, как (что я сам реализую). Используя это, автоматически сгенерированный код будет сгенерирован так, что любое значение даты теперь будет DateTime (например, Date) вместо String. Хорошо!

Так что я подумал, почему бы не использовать это в наших интересах? Мы также получаем hex-цвета от этого API. Итак, мы сделали так, чтобы API возвращал шестнадцатеричный код ("#FFFFFF") как класс HexColorCode. По умолчанию это просто превратится в String, поэтому я должен инициализировать UIColor с помощью hex везде, где я хочу его использовать. Но сейчас я пытаюсь использовать тот же лог c, чтобы у автоматически сгенерированных классов был UIColor, который я могу использовать везде. Но вышесказанное происходит.

Я предполагаю, что Date, будучи public struct из Foundation, обладает некоторой свободой, которой не обладает UIColor, open class из UIKit, унаследованной от NSObject , Но что и почему?


Я думаю, что возможно создать объект-оболочку, так что я могу сказать, что "HexColorCode" - это отдельный класс, который имеет одно поле color, и Я бы сказал myView.backgroundColor = apiModel.color.color вместо apiModel.color. Но я действительно хотел, чтобы это сработало ..

1 Ответ

1 голос
/ 14 января 2020

Я проверил вашу ситуацию, и у меня также сложилось впечатление, что компилятор запутался.
Но может быть решение. Следующий код компилируется для меня без проблем:

public protocol MyProtocol {
    init(myValue: Any) throws
}

class MyColor:UIColor {
    convenience init(myValue: Any) throws {
    self.init(red: 0, green: 0, blue: 0, alpha: 1)
    }
}

РЕДАКТИРОВАТЬ:

Извините: хотя этот код компилируется, он пропускает протокол.
Вот (надеюсь) правильный код:

class MyColor:UIColor, MyProtocol {
    required convenience init(myValue: Any) throws {
    self.init(red: 0, green: 0, blue: 0, alpha: 1)
    }
}
...