2

I want to compare two UIColors, however nothing works. I even wrote this function to compare the RGB values of these color:

-(BOOL)compare:(UIColor*)colorA withColor:(UIColor*)colorB{
    CGFloat redA = 0.0, greenA = 0.0, blueA = 0.0, alphaA =0.0;
    [colorA getRed:&redA green:&greenA blue:&blueA alpha:&alphaA];

    CGFloat redB = 0.0, greenB = 0.0, blueB = 0.0, alphaB =0.0;
    [colorB getRed:&redB green:&greenB blue:&blueB alpha:&alphaB];

    NSLog(@"A - %f, %f, %f", redA, greenA, blueA);
    NSLog(@"B - %f, %f, %f", redB, greenB, blueB);

    if (redA == redB && greenA == greenB && blueA == blueB) {
        return  true;
    }else{
        NSLog("false");
        return false;
    }
}

And it return this, which I don't really get:

2014-03-21 21:57:09.481 TextEdit[6863:70b] A - 0.411765, 0.803922, 0.117647
2014-03-21 21:57:09.481 TextEdit[6863:70b] B - 0.411765, 0.803922, 0.117647
2014-03-21 21:57:09.482 TextEdit[6863:70b] false

So it is equal, yet it returns false. Any suggestions?

rmaddy
  • 314,917
  • 42
  • 532
  • 579
adam
  • 807
  • 3
  • 11
  • 17
  • Does `isEqual:` not help? One would assume Apple overrode this from `NSObject` and compares colors properly. – Scott Berrevoets Mar 21 '14 at 21:05
  • No it return false as well. I'm converting one of these colors from CIColor, but I don't know if that could be a problem. – adam Mar 21 '14 at 21:06
  • First, there should never be a case when comparing color objects is necessary. Second, problem in your code is that comparing floats with `==` never works reliably. Floats doesn't represent numbers exactly. – Sulthan Mar 21 '14 at 21:16
  • One serious flaw here - you are assuming RGB colors. Pass in `[UIColor whiteColor` and `[UIColor colorWithRed:1 green:1 blue:1 alpha:1]` and this won't work because they are different color models. Be sure to check the return value of `getRed:green:blue:alpha:`. If it returns `NO`, try one of the related methods like `getWhite:alpha:`. – rmaddy Mar 21 '14 at 21:30
  • 1
    One other little nitpick - you should use `YES` and `NO` with `BOOL`, not `true` and `false`. – rmaddy Mar 21 '14 at 21:32

2 Answers2

3

You shouldn't use operator == for comparing floating-point numbers (float, double, CGFloat etc) because of the way the number is stored (rounding etc). Instead what you should do is compare if the color components are in a certain range of each other. I think 1.0/255.0 should be ok.

So what you should do is

const CGFloat kRange = 1.0/255.0;
if (fabs(redA - redB) < kRange &&
    fabs(greenA - greenB) < kRange &&
    fabs(blueA - blueB) < kRange &&
    fabs(alphaA - alphaB) < kRange)
{
    return true;
}
else
{
    return false;
}
kap
  • 842
  • 4
  • 16
-2

I don't have my mac on me, but have you tried:

if([colorA isEqual:colorB]) {
  // true
} else {
  // false
}

If anything, check out this post (How to compare UIColors?). Hopefully that'll shed some more light on the subject for ya.

Community
  • 1
  • 1
ebandersen
  • 2,362
  • 26
  • 25
  • If you extract the color components from `UIColor`, they are primitives, which you do compare using ==. – Scott Berrevoets Mar 21 '14 at 21:09
  • I edited my post with the reference I was pulling my suggestion from. Hopefully it'll help. – ebandersen Mar 21 '14 at 21:14
  • `redA`, `redB`, etc. are `CGFloat`. You can't use `isEqual:` with primitive types. – rmaddy Mar 21 '14 at 21:31
  • With all fairness, the question title is "comparing UIColors" not "comparing floats". My response is still the correct way to compare UIColor objects. See the reference I have in my post – ebandersen Mar 21 '14 at 21:33
  • Look at the OP's code. The variables you reference in your answer are clearly not `UIColor` objects. – rmaddy Mar 21 '14 at 22:18
  • That's why I said "You would just need to create another color object for each value and compare those UIColor objects directly." meaning he should create UIColor objects and compare those directly instead of the primitive values. – ebandersen Mar 21 '14 at 22:33