web-dev-qa-db-ja.com

UIColorなどの既存のUIKitクラスに拡張機能で初期化子を追加する方法は?

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()

  }
}

解決策はありますか?

25
mrahmiao

次のように独自のイニシャライザーを作成するには、このようにはできません。別のパラメーター名を選択する必要があります。

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)
33
Leo Dabus

まあ、本当に、本当に、本当に初期化子をオーバーライドしたい場合は、方法があります。

さらに読む前に:これをchangeUIKitの動作にしないでください。どうして? 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 // 
        ///////////////////////////         

    }

}

説明

これは、Swiftから呼び出されるObjective-Cの動的な性質を使用して、実行時にメソッド定義ポインターを交換します。これが何を意味するのか、またはその意味がわからない場合は、このコードを使用する前にトピックを読むことをお勧めします。

2
Jordan Smith

パラメータタイプの変更も機能します。

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で割るという冗長な作業を忘れてしまいます。そのため、私はこの方法を使って自分を容易にしました。