CGPoint
を CGPoint(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
}
}
これで、CGFloat
、Double
, Float
などに一度で対応できるかと思いきや、イニシャライザの中で、ジェネリックな x
を CGFloat
や Double
に変換できない事に気がつきました。
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)
}
}
いい感じです。こうなると調子に乗ってよく使う CGSize
や CGRect
にも手を出してみる事にします。
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)