UIColor の比較時の注意点

  • 7
    Like
  • 0
    Comment

UIColor の比較

UIColor を比較する時に isEqual メソッド使用することができます。しかし、UIColor の whiteColor, blackColor で取得した UIColor を比較する時に問題が発生することがあります。

通常の場合

例えば次のように青色同士を比較する場合は問題ありません。

UIColor color = [UIColor colorWithRed:0.0f green:0.0f blue:1.0f alpha:1.0f];
UIColor* blueColor = [UIColor blueColor];
NSLog(@"Compare color to blue by isEqual: %@", [color isEqual:blueColor] ? @"YES" : @"NO");

実行結果

Compare color to blue by isEqual: YES

whiteColor の場合

しかし、whiteColor の場合上記のような方法だとうまくいきません。例えば次のようなコード

UIColor* color = [UIColor colorWithRed:1.0f green:1.0f blue:1.0f alpha:1.0f];
UIColor* white = [UIColor whiteColor];

CGFloat red, green, blue, alpha;
[color getRed:&red green:&green blue:&blue alpha:&alpha];
NSLog(@"color -> red:%lf, green:%lf, blue:%lf, alpha:%lf",red, green, blue, alpha);

[white getRed:&red green:&green blue:&blue alpha:&alpha];
NSLog(@"white -> red:%lf, green:%lf, blue:%lf, alpha:%lf",red, green, blue, alpha);

NSLog(@"color is %@", color.description);
NSLog(@"white is %@", white.description);
NSLog(@"Compare color to white by isEqual: %@, CGColorEqaulToColor: %@",
      [color isEqual:white] ? @"YES" : @"NO",
      CGColorEqualToColor(color.CGColor, white.CGColor) ? @"YES" : @"NO");

実行結果


color -> red:1.000000, green:1.000000, blue:1.000000, alpha:1.000000
white -> red:1.000000, green:1.000000, blue:1.000000, alpha:1.000000
color is UIDeviceRGBColorSpace 1 1 1 1
white is UIDeviceWhiteColorSpace 1 1

Compare color to white by isEqual: NO, CGColorEqaulToColor: NO

 それぞれの RGBA の値は一緒ですが、isEqual や CGColorToColor の比較結果は NO になっています。

原因はカラースペース

それぞれの UIColor の description を見てもらうと RGBA を指定して作成したインスタンスは、UIDeviceRGBColorSpace になっているのに対して、whiteColor で取得した UIColor は UIDeviceWhiteColorSpace になっています。
このため、RGBA の値は一緒でもオブジェクトどうしの比較の際に NO となってしまうようです。

ちなみに HSB 値を指定して生成した場合は UIDeviceRGBColorSpace になるようです。

UIColor* color = [UIColor colorWithRed:1.0f green:1.0f blue:1.0f alpha:1.0f];
UIColor* hsb = [UIColor colorWithHue:0.0f saturation:0.0f brightness:1.0f alpha:1.0f];

CGFloat red, green, blue, alpha;
[color getRed:&red green:&green blue:&blue alpha:&alpha];
NSLog(@"color -> red:%lf, green:%lf, blue:%lf, alpha:%lf",red, green, blue, alpha);
[hsb getRed:&red green:&green blue:&blue alpha:&alpha];
NSLog(@"hsb -> red:%lf, green:%lf, blue:%lf, alpha:%lf",red, green, blue, alpha);

NSLog(@"color is %@", color.description);
NSLog(@"hsb is %@", hsb.description);

NSLog(@"Compare color to hsb by isEqual: %@, CGColorEqaulToColor: %@",
      [color isEqual:hsb] ? @"YES" : @"NO",
      CGColorEqualToColor(color.CGColor, hsb.CGColor) ? @"YES" : @"NO");

実行結果


color -> red:1.000000, green:1.000000, blue:1.000000, alpha:1.000000
hsb -> red:1.000000, green:1.000000, blue:1.000000, alpha:1.000000
color is UIDeviceRGBColorSpace 1 1 1 1
hsb is UIDeviceRGBColorSpace 1 1 1 1

Compare color to hsb by isEqual: YES, CGColorEqaulToColor: YES

解決方法

解決方法としては比較する時は RGBA 値を直接比較した方が安全なようです。

@interface UIColor (Compare)

- (BOOL)isEqualToColor:(UIColor*)color;

@end

@implementation UIColor (Compare)

- (BOOL)isEqualToColor:(UIColor *)color
{
    CGFloat myRed, myGreen, myBlue, myAlpha;
    [self getRed:&myRed green:&myGreen blue:&myBlue alpha:&myAlpha];

    CGFloat otherRed, otherGreen, otherBlue, otherAlpha;
    [color getRed:&otherRed green:&otherGreen blue:&otherBlue alpha:&otherAlpha];

    return (myRed == otherRed && myGreen == otherGreen && myBlue == otherBlue && myAlpha == otherAlpha);
}

@end