swift 如何在现有UIKit类(如UIColor)的扩展中添加初始化器?

i5desfxk  于 2023-09-30  发布在  Swift
关注(0)|答案(3)|浏览(109)

Swift文档说在扩展中添加初始化器是可能的,文档中的示例是关于向 struct 添加初始化器的。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()

  }
}

有什么办法吗?

dauxcl2d

dauxcl2d1#

你不能这样做,你必须选择不同的参数名来创建你自己的初始化器/你也可以让它们通用以接受任何BinaryFloatingPoint或BinaryFloatingPoint类型:

extension UIColor {
    convenience init<T: BinaryInteger>(r: T, g: T, b: T, a: T = 255) {
        self.init(red: .init(r)/255, green: .init(g)/255, blue: .init(b)/255, alpha: .init(a)/255)
    }
    convenience init<T: BinaryFloatingPoint>(r: T, g: T, b: T, a: T = 1.0) {
        self.init(red: .init(r), green: .init(g), blue: .init(b), alpha: .init(a))
    }
}
let green1 = UIColor(r: 0, g: 255, b: 0, a: 255)  // r 0,0 g 1,0 b 0,0 a 1,0
let green2 = UIColor(r: 0, g: 1.0, b: 0, a: 1.0)  // r 0,0 g 1,0 b 0,0 a 1,0

let red1 = UIColor(r: 255, g: 0, b: 0)  // r 1,0 g 0,0 b 0,0 a 1,0
let red2 = UIColor(r: 1.0, g: 0, b: 0)  // r 1,0 g 0,0 b 0,0 a 1,0
bcs8qyzn

bcs8qyzn2#

好吧,如果你真的,真的,真的想覆盖一个初始化器,有一个方法。

在您进一步阅读之前:永远不要这样做来 * 改变 * UIKit行为。为什么?它可能会让那些不明白为什么UIColor初始化器没有正常工作的人感到困惑。仅在修复UIKit错误或添加功能等情况下执行此操作。

我已经使用以下方法修补了几个iOS bug。

代码

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 // 
        ///////////////////////////         

    }

}

说明

这是使用Swift调用的J2EE-C的动态特性,在运行时交换方法定义指针。如果您不知道这意味着什么,或者它的含义,那么在使用这段代码之前阅读一下这个主题可能是一个好主意。

ua4mk5z4

ua4mk5z43#

更改参数类型也将起作用。

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的冗余工作。所以我做了这个方法来方便我。

相关问题