LoginSignup
31
33

More than 5 years have passed since last update.

CGPoint をちょっと便利にしようと思ったら、結構便利になってしまった話

Last updated at Posted at 2016-10-13

CGPointCGPoint(x: 100, y: 200) なんて何千回(ウソって?)も書いていると、x:, y: がやっぱり面倒になってきて、x:y: を省略できるイニシャライザを extension で書こうと思った。

extension CGPoint {
    init(_ x: CGFloat, _ y: CGFloat) {
        self.x = x
        self.y = y
    }
}

なんかこう書いてみると、CGFloat だけでなく、Double, Float などいろいろな種類を同時に対応できないものかと思うようになりました。そこで、こんなイニシャライザがあれば、便利だと思いました。

extension CGPoint {
    init<T: FloatingPoint, U: FloatingPoint >(_ x: T, _ y: U) {
        // initializer
    }
}

これで、CGFloatDouble, Float などに一度で対応できるかと思いきや、イニシャライザの中で、ジェネリックな xCGFloatDouble に変換できない事に気がつきました。

    let cx = CGFloat(x) // error
    let dx = Double(x) // error

ここで皆さんに助けを求めようと文章を考えている時に、ちょっと閃きました。これがあるからエンジニアはやめられない。

作戦はこうです。まずは なんでも、CGFloat に変換できるプロトコルを用意します。

protocol CGFloatCovertible {
    var cgFloatValue: CGFloat { get }
}

そこで、CGPoint でよく使いそうな、型の CGFloatCovertible extension を用意します。そこでは、元の値を CGFloat に変換して戻してあげます。

extension CGFloat: CGFloatCovertible {
    var cgFloatValue: CGFloat { return self }
}

extension Float: CGFloatCovertible {
    var cgFloatValue: CGFloat { return CGFloat(self) }
}

extension Double: CGFloatCovertible {
    var cgFloatValue: CGFloat { return CGFloat(self) }
}

extension Int: CGFloatCovertible {
    var cgFloatValue: CGFloat { return CGFloat(self) }
}

これで、CGPoint の イニシャライザを用意してあげれば結構万能なイニシャライザが出来上がりました。

extension CGPoint {
    init<T: CGFloatCovertible, U: CGFloatCovertible>(_ x: T, _ y: U) {
        self = CGPoint(x: x.cgFloatValue, y: y.cgFloatValue)
    }
}

いい感じです。こうなると調子に乗ってよく使う CGSizeCGRect にも手を出してみる事にします。

extension CGPoint {
    init<X: CGFloatCovertible, Y: CGFloatCovertible>(_ x: X, _ y: Y) {
        self = CGPoint(x: x.cgFloatValue, y: y.cgFloatValue)
    }
}

extension CGSize {
    init<W: CGFloatCovertible, H: CGFloatCovertible>(_ w: W, _ h: H) {
        self = CGSize(width: w.cgFloatValue, height: h.cgFloatValue)
    }
}

extension CGRect {
    init<X: CGFloatCovertible, Y: CGFloatCovertible, W: CGFloatCovertible, H: CGFloatCovertible>(_ x: X, _ y: Y, _ w: W, _ h: H) {
        self = CGRect(x: x.cgFloatValue, y: y.cgFloatValue, width: w.cgFloatValue, height: h.cgFloatValue)
    }
}

これで、以前の記事「Swift で 半精度浮動小数点数 (16 bit Float) を扱う」で扱ったような、特殊な数値型な数値型でも、extension で対応可能なので、必要に応じて対応可能になります。

extension Float16: CGFloatCovertible {
    var cgFloatValue: CGFloat { return CGFloat(self.floatValue) }
}

Gist

ソースコードはこちらから入手できます。

環境に関する表記

Xcode Version 8.0 (8A218a)
Apple Swift version 3.0 (swiftlang-800.0.46.2 clang-800.0.38)
31
33
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
31
33