読者です 読者をやめる 読者になる 読者になる

面白きことは良きことなり

拙く未熟なiOSエンジニアの備忘録と戯言

UIColorの比較で単純に==や!=してはいけない話(Swift3コード追記)

UIColorの比較の注意点

UIColor同士を比較する際、==!=で比較することは可能。 しかし、安易にこの比較を行なった場合、意図しない挙動になることもある。

その例が下記となる f:id:aryzae:20170520162714p:plain

UIColorの作成時、white値を指定して作成することもできれば、rgba値を指定して作成することもできる。 この作成の仕方で、同じ色でも比較時にfalseが返る。

Objective-Cの時、UIColor.whiteUIColor(white: 1, alpha: 1) で作成したインスタンスは同じアドレスを挿していた。そのため、== の比較でも同じオブジェクトを指していたのでtrueになるのは当然だった。

Swift3で同じ様にアドレスを確認すると、別のアドレスを指しているのが画像からわかる。つまり別オブジェクトでも同一とのものと判定されていることがわかる。

同じ色でもfalseが返る理由

では、なぜ同じ色なのに比較するとfalseが返るか。 それはdumpで見るとわかる。

f:id:aryzae:20170520165104p:plain

このように同じ色でも、インスタンスの生成の仕方で継承しているクラスが異なっているためである。

生成方法に左右されない比較方法

生成方法が異なっていても、楽に比較するため==で比較できるようにメソッドを 書くのが良さそう。

// Swift3
func ==(lhs: UIColor, rhs: UIColor) -> Bool {
    var lhsRed: CGFloat = 0.0
    var lhsGreen: CGFloat = 0.0
    var lhsBlue: CGFloat = 0.0
    var lhsAlpha: CGFloat = 0.0
    lhs.getRed(&lhsRed, green: &lhsGreen, blue: &lhsBlue, alpha: &lhsAlpha)

    var rhsRed: CGFloat = 0.0
    var rhsGreen: CGFloat = 0.0
    var rhsBlue: CGFloat = 0.0
    var rhsAlpha: CGFloat = 0.0
    rhs.getRed(&rhsRed, green: &rhsGreen, blue: &rhsBlue, alpha: &rhsAlpha)

    return lhsRed == rhsRed && lhsGreen == rhsGreen && lhsBlue == rhsBlue && lhsAlpha == rhsAlpha
}

参考: UIColor の比較時の注意点 - Qiita

これで==で比較できるようになった。

f:id:aryzae:20170520170915p:plain


別案として、規約で縛る代わり==!=を許可するのも手だと思う。

具体的に言うと、下記を守れば==!=で比較しても正しく判定できる

  • UIColor生成時、rgbaを指定して作成する
  • UIColorが持つredColorやwhiteColorは使用しない