Подтвердить что ты не робот

Как добавить инициализаторы в расширения существующих классов UIKit, таких как UIColor?

В документе Swift говорится, что добавление инициализаторов в расширение возможно, а пример в документе - это добавление инициализатора в стойку. Xcode не может связать назначенный инициализатор UIColor в моем инициализаторе удобства:

extension UIColor {
  convenience init(rawValue red: CGFloat, green g: CGFloat, blue b: CGFloat, alpha a: CGFloat) {

    // Can not find out the designated initializer here
    self.init()

  }
}

Любые решения?

4b9b3361

Ответ 1

Вы не можете сделать это так, вы должны выбрать разные имена параметров, чтобы создать свои собственные инициализаторы, как показано ниже:

extension UIColor {
    convenience init(r: UInt8, g: UInt8 , b: UInt8 , a: UInt8) {
        self.init(red: CGFloat(r)/255, green: CGFloat(g)/255, blue: CGFloat(b)/255, alpha: CGFloat(a)/255)
    }
    convenience init(r: Double, g: Double , b: Double , alpha: Double) {
        self.init(red: CGFloat(r), green: CGFloat(g), blue: CGFloat(b), alpha: CGFloat(alpha))
    }
}

let myGreenColor1 = UIColor(r: 0, g: 255, b: 0, a: 255)
let myGreenColor2 = UIColor(r: 0, g: 1, b: 0, alpha: 1)

Ответ 2

Ну, если вы действительно, действительно, действительно хотите переопределить инициализатор, есть способ.

Прежде чем читать дальше: никогда не делайте этого, чтобы изменить поведение UIKit. Зачем? Это может запутать кого-то, кто не может понять, почему инициализатор UIColor не выполняет то, что он обычно делает. Только сделайте это, чтобы исправить ошибку UIKit или добавить функциональность и т.д.

Я использовал следующее для исправления нескольких ошибок iOS.

код

extension UIColor {

    private static var needsToOverrideInit = true

    override open class func initialize() {

        // Only run once - otherwise subclasses will call this too. Not obvious.

        if needsToOverrideInit {
            let defaultInit = class_getInstanceMethod(UIColor.self, #selector(UIColor.init(red:green:blue:alpha:)))
            let ourInit = class_getInstanceMethod(UIViewController.self, #selector(UIColor.init(_red:_green:_blue:_alpha:)))
            method_exchangeImplementations(defaultInit, ourInit)
            needsToOverrideInit = false
        }

    }

    convenience init(_red: CGFloat, _green: CGFloat, _blue: CGFloat, _alpha: CGFloat) {

        // This is trippy. We swapped implementations... won't recurse.
        self.init(red: _red, green: _green, blue: _blue, alpha: _alpha)

        /////////////////////////// 
        // Add custom logic here // 
        ///////////////////////////         

    }

}

Описание

Это использует динамический характер Objective-C, вызываемый из Swift, для переопределения указателей определения метода во время выполнения. Если вы не знаете, что это значит, или его последствия, вероятно, неплохо прочитать эту тему, прежде чем использовать этот код.

Ответ 3

Будет также изменено изменение типов параметров.

extension UIColor {

    convenience init(red: Int, green: Int, blue: Int, alpha: CGFloat) {

        let normalizedRed = CGFloat(red) / 255
        let normalizedGreen = CGFloat(green) / 255
        let normalizedBlue = CGFloat(blue) / 255

        self.init(red: normalizedRed, green: normalizedGreen, blue: normalizedBlue, alpha: alpha)
    }
}

Использование

let newColor: UIColor = UIColor.init(red: 74, green: 74, blue: 74, alpha: 1)

Обычно я забыл избыточную работу по делению значений компонентов на 255. Поэтому я сделал этот метод для облегчения.