UIColor
Compare Colors
iOS Development
Swift Programming
User Interface

How to compare UIColors?

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

Introduction

Comparing two UIColor values sounds simple, but it gets tricky once you include color spaces, grayscale colors, dynamic system colors, and alpha. Two colors can look the same while being created differently, and two UIColor objects can be different instances even when they represent the same visual color. A good comparison strategy depends on what “equal” is supposed to mean in your app.

Start With the Simplest Check

For many ordinary static colors, isEqual is enough:

swift
1import UIKit
2
3let a = UIColor.red
4let b = UIColor(red: 1, green: 0, blue: 0, alpha: 1)
5
6print(a.isEqual(b))

This often works, but it is not always the most robust choice when colors come from different color spaces or from dynamic system definitions.

Compare RGBA Components Explicitly

A practical approach is to convert both colors to RGBA components and compare those numbers:

swift
1import UIKit
2
3func rgbaComponents(of color: UIColor) -> (CGFloat, CGFloat, CGFloat, CGFloat)? {
4    var r: CGFloat = 0
5    var g: CGFloat = 0
6    var b: CGFloat = 0
7    var a: CGFloat = 0
8
9    guard color.getRed(&r, green: &g, blue: &b, alpha: &a) else {
10        return nil
11    }
12
13    return (r, g, b, a)
14}
15
16func colorsEqual(_ lhs: UIColor, _ rhs: UIColor) -> Bool {
17    guard let lc = rgbaComponents(of: lhs), let rc = rgbaComponents(of: rhs) else {
18        return false
19    }
20    return lc == rc
21}
22
23print(colorsEqual(.red, UIColor(red: 1, green: 0, blue: 0, alpha: 1)))

This is a strong choice when you want component-level equality and your colors can be expressed in RGB.

Be Careful With Dynamic Colors

On modern iOS, some colors are dynamic. UIColor.label, for example, resolves differently in light mode and dark mode. Comparing the color object directly without resolving it against a trait collection may not reflect what the user actually sees.

Resolve the colors first:

swift
1import UIKit
2
3func resolvedEqual(_ lhs: UIColor, _ rhs: UIColor, traits: UITraitCollection) -> Bool {
4    let left = lhs.resolvedColor(with: traits)
5    let right = rhs.resolvedColor(with: traits)
6    return colorsEqual(left, right)
7}
8
9let traits = UITraitCollection(userInterfaceStyle: .light)
10print(resolvedEqual(.label, .black, traits: traits))

This is important whenever appearance mode can change the meaning of the color.

A Tolerance-Based Comparison

Sometimes exact floating-point equality is stricter than you want. If colors are generated through calculations, tiny rounding differences may appear.

A tolerance-based helper is safer in those cases:

swift
1import UIKit
2
3func close(_ a: CGFloat, _ b: CGFloat, tolerance: CGFloat = 0.0001) -> Bool {
4    abs(a - b) < tolerance
5}
6
7func colorsNearlyEqual(_ lhs: UIColor, _ rhs: UIColor) -> Bool {
8    guard let lc = rgbaComponents(of: lhs), let rc = rgbaComponents(of: rhs) else {
9        return false
10    }
11
12    return close(lc.0, rc.0)
13        && close(lc.1, rc.1)
14        && close(lc.2, rc.2)
15        && close(lc.3, rc.3)
16}

This is helpful if the colors come from blending, animation, or conversion work.

Comparing cgColor

You may also see code comparing cgColor values:

swift
let equal = color1.cgColor == color2.cgColor

That can work in some cases, but it is not always the best semantic comparison because the underlying representation can differ depending on color space and origin.

Use it when you specifically care about the underlying Core Graphics color identity, not just visible equivalence.

What “Equal” Should Mean in Practice

There are at least three useful meanings of equality here:

  • same object or equivalent UIKit color definition
  • same resolved visible RGBA value
  • close enough for rendering or testing purposes

For UI testing and theming, resolved RGBA comparison is often the most useful. For low-level rendering or caching, cgColor identity might matter more.

Common Pitfalls

The biggest pitfall is assuming two UIColor instances can be compared meaningfully with object identity alone. Different objects can still represent the same visual color.

Another common issue is forgetting about dynamic system colors. UIColor.label is not one fixed RGBA value across all trait environments.

People also often rely on getRed without realizing that some colors may not convert cleanly into the expected RGB representation. In those cases, your helper should fail safely rather than returning nonsense.

Finally, exact equality can be too strict if the colors were produced by calculation. A tolerance-based comparison is often more realistic for generated values.

Summary

  • 'UIColor comparison is easy only when the colors are simple static values.'
  • For robust equality, compare resolved RGBA components rather than object identity.
  • Resolve dynamic colors against a UITraitCollection before comparing them.
  • Use a tolerance when tiny floating-point differences are acceptable.
  • Choose the comparison strategy that matches what “equal” means in your app.

Related reading
Free course
Beginner
7 lessons
2 hours
Tackling System Design Interview Problems

A short course that equips you with the skills to approach system design interviews methodically.

Start the free course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

All Rights Reserved.