SoFunction
Updated on 2025-04-13

The difference between the UIColor class and its related classes and the method of judging equality in iOS

The difference and connection between UIColor, CGColor, and CIColor
 
I recently looked at CoreGraphics stuff and saw something about CGColor, so I thought about taking a look at UIColor, CIColor, and figuring out the differences and connections between them. Let's take a look at the three concepts:
 
1. UIColor
 
UIColor is an important class in UIKit that stores color information. A UIColor object contains the values ​​of color and transparency, and its color space has been optimized for IOS. UIColor contains some class methods for creating some of the most common colors, such as white, black, red, transparent colors, etc. The color spaces of these colors are also different (white and black are kCGColorSpaceDeviceGray, and the color space of red is kCGColorSpaceDeviceRGB).
 
In addition, UIColor has two important properties: one is CGColor and the other is CIColor (added after 5.0). These two properties can connect the three objects of UIColor, CGColor, and CIColor. The conversion between these three will be described in detail later.
 
 
 
2. CGColor
 
CGColor is mainly used in the CoreGaphics framework. CGColor is actually a structure, and we usually use its reference type CGColorRef when using CGColor. CGColor is mainly composed of two parts: CGColorSapce and Color Components. The same color is composed of. If the color space is different, the parsed results may be different. This is just like when we process image data, we can imagine the results of treating RGBA format as BGRA format. In Quartz 2D, CGColor is often used to set the fill color of the context, set transparency, etc.
 
1. How to create a CGColor. The most commonly used function is CGColorCreate. This function has two parameters:
 
1) colorspace, specify the color space corresponding to CGColor, and Quartz will retain the object, so you can safely release the object after the call.
 
2) components, an array of CGFloats, the number of elements in the array is the number of color components n contained in the specified color space, plus the corresponding alpha value.
 
This function should return a newly created CGColorRef. When we no longer use the object, we use the CGColorRelease function to release the object.
 
2. Obtain CGColor data
 
When we create, we pass in two important parameters. When we get CGColorRef, we can of course get the corresponding ColorSpace and Components.
 
1) Get ColorSpace
 
Through the CGColorGetColorSpace function, we can get the ColorSpace corresponding to the current CGColorRef. This function only accepts one parameter, which is that you want to get the ColorSpace's CGColorRef. Here is a simple example:

Copy the codeThe code is as follows:

CGColorRef cgColor = [UIColor redColor].CGColor;
CGColorSpaceRef colorSpace = CGColorGetColorSpace(cgColor);
NSLog(@"color space: %@", colorSpace);

2) Get Color Components
 
To get the color value corresponding to CGColorRef, we need to use two functions: CGColorGetNumberOfComponents and CGColorGetComponents. Let's first look at the function prototypes of two functions:
 

Copy the codeThe code is as follows:

size_t CGColorGetNumberOfComponents (
   CGColorRef color
);

const CGFloat * CGColorGetComponents (
   CGColorRef color
);


The first function is to obtain the number of color components contained in CGColorRef, and the second function is to obtain the array of actual color components. Let's see a small example:

Copy the codeThe code is as follows:

NSUInteger num = CGColorGetNumberOfComponents(cgColor);
const CGFloat *colorComponents = CGColorGetComponents(cgColor);
for (int i = 0; i < num; ++i) {
    NSLog(@"color components %d: %f", i, colorComponents[i]);
}

 
 
3. CIColor
 
CIColor is mainly used with other classes in the Core Image framework, such as CIFilter, CIContext and CIImage. Today, the color value part we are mainly concerned about is the range of color values ​​in CIColor between 0.0 and 1.0.0 means that the color component is the minimum value, and 1.0 means that the color component is the maximum value. The range of alpha values ​​is also between 0.0 and 1.0, 0.0 means fully transparent, 1.0 means completely opaque, and CIColor's color components are usually not multiplied by the alpha value.
 
We can use the initWithCGColor: function to create a CIColor through CGColor. The incoming CGColorRef object can make any color space, but the Core Image framework will convert all color spaces to the core image working color space before passing in the filter kernel. The core image working color space uses three color components plus an alpha component (actually kCGColorSpaceDeviceRGB). In the following example, we verify this.
 
 
 
4. The difference and connection between UIColor, CGColor, and CIColor
 
1. Two attributes of UIColor CGColor, CIColor
 
UIColor's CGColor is always valid. Whether it is created through CGColor, CIColor, or other methods, the CGColor attribute is always valid; but the CIColor attribute is not always valid. It is only valid when UIColor is created through CIColor, otherwise an exception will be thrown when accessing the property. Here is a small example:
 

Copy the codeThe code is as follows:

// test init uicolor with CGColor
UIColor *color = [UIColor colorWithCGColor:[UIColor whiteColor].CGColor];
   
// CGColor property is always valid
NSLog(@"CGColor from UIColor %@", );

// don't use CIColor property
// This property throws an exception if the color object was not initialized with a Core Image color.
NSLog(@"CIColor from UIColor %@", );   // crush


2. UIColor is initialized using CGColor
 
When UIColor is initialized using CGColor, all the information contained in CGColorRef will be retained intact, including Color space. And through the following small examples, we can also see that if UIColor is initialized using CGColor, UIColor actually directly retains a CGColorRef object. Examples are as follows:
 

Copy the codeThe code is as follows:

// test kCGColorSpaceDeviceCMYK
CGColorSpaceRef cmykSpace = CGColorSpaceCreateDeviceCMYK();
CGFloat cmykValue[] = {1, 1, 0, 0, 1};      // blue
CGColorRef colorCMYK = CGColorCreate(cmykSpace, cmykValue);
CGColorSpaceRelease(cmykSpace);
NSLog(@"colorCMYK: %@", colorCMYK);
   
// color with CGColor, uicolor will just retain it
UIColor *color = [UIColor colorWithCGColor:colorCMYK];
NSLog(@"CGColor from UIColor: %@", );


3. UIColor is initialized using CIColor
 
Let’s discuss below that when using CIColor to initialize a UIColor and then accessing the CGColor property of UIColor, we will find that the color space of CGColor is not exactly the same as the color space of CIColor. In this process, CIColor will make a conversion for us. Let's take a look at the three color spaces of kCGColorSpaceDeviceGray, kCGColorSpaceDeviceRGB, and kCGColorSpaceDeviceCMYK to initialize a CIColor, then use the CIColor to initialize a UIColor, and then access its CIColor attributes and CGColor attributes, view the color space and print the color information.
 
1) Initialize CIColor using kCGColorSpaceDeviceGray
 
First look at the code:
 

Copy the codeThe code is as follows:

 // test kCGColorSpaceDeviceGray
NSLog(@"CGColor white color:%@", [UIColor whiteColor].CGColor);

CIColor *ciColor = [CIColor colorWithCGColor:[UIColor whiteColor].CGColor];
NSLog(@"cicolor: %@", ciColor);
NSLog(@"cicolor colorspace: %@", );
   
color = [UIColor colorWithCIColor:ciColor];
NSLog(@"color %@", color);
   
// Core Image converts all color spaces to the Core Image working color
// space before it passes the color space to the filter kernel.
// kCGColorSpaceDeviceGray ---> kCGColorSpaceDeviceRGB
NSLog(@"cicolor from UIColor: %@", );
NSLog(@"cicolor's colorspace: %@", );
NSLog(@"color's CGColor: %@", );


By running the program, we can see that if we use a CGColor of the color space of the kCGColorSpaceDeviceGray to initialize the CIColor, we can see that the color space of the CIColor has always been kCGColorSpaceDeviceGray. By accessing the CIColor property of the UIColor, we can see that its color space is still kCGColorSpaceDeviceGray, but when accessing the CGColor property of the UIColor, we can find that its color space has been converted into a kCGColorSpaceDeviceRGB space, and the color value is correctly converted from the original color space to the new color space.
 
2) Initialize CIColor using kCGColorSpaceDeviceRGB
 
Let's look at the code the same:
 

Copy the codeThe code is as follows:

 //test kCGColorSpaceDeviceRGB
NSLog(@"CGColor red color:%@", [UIColor redColor].CGColor);
   
CIColor *ciColor = [CIColor colorWithCGColor:[UIColor redColor].CGColor];
NSLog(@"cicolor: %@", ciColor);
NSLog(@"cicolor colorspace: %@", );
   
UIColor *color = [UIColor colorWithCIColor:ciColor];
NSLog(@"color %@", color);
   
NSLog(@"cicolor from UIColor: %@", );
NSLog(@"cicolor's colorspace: %@", );
NSLog(@"color's CGColor: %@", );


During the whole process, the values ​​accessed through the CGColor and CIColor properties of UIColor, we can print them and find that they are all kCGColorSpaceDeviceRGB space.
 
4. Initialize CIColor using kCGColorSpaceDeviceCMYK
 
Let's continue to see a piece of code:
 

Copy the codeThe code is as follows:

// test kCGColorSpaceDeviceCMYK
CGColorSpaceRef cmykSpace = CGColorSpaceCreateDeviceCMYK();
NSLog(@"Components number: %zu", CGColorSpaceGetNumberOfComponents(cmykSpace));
CGFloat cmykValue[] = {1, 1, 0, 0, 1};      // blue
CGColorRef colorCMYK = CGColorCreate(cmykSpace, cmykValue);
CGColorSpaceRelease(cmykSpace);
NSLog(@"colorCMYK: %@", colorCMYK);
   
ciColor = [CIColor colorWithCGColor:colorCMYK];
NSLog(@"cicolor: %@", ciColor);     // in fact,the color value of CIColor has converted to RGB Colorspace
NSLog(@"cicolor colorspace: %@", );
   
color = [UIColor colorWithCIColor:ciColor];
NSLog(@"UIColor with CIColor: %@", color);
   
NSLog(@"cicolor from UIColor: %@", );
NSLog(@"cicolor's colorspace: %@", );
   
// when UIColor init with CIColor, UIColor's CGColor will convert other colorspace to kCGColorSpaceDeviceRGB
NSLog(@"cgcolor from UIColor: %@", );


During the whole process, we can also find that when we use a CGColor of CMYK color space to initialize CIColor, the color space of CIColor is still CMYK, but the color value has been converted to RGB color value. When we use this CIColor to create a UIColor, when we print information through the CIColor and CGColor properties, we will find that the color space of CIColor is still CMYK, but the information obtained by printing CGColor means that it has been converted into RGB space.
 
 
 
5. UIColor extension, how to determine whether two colors are equal
 
As mentioned earlier, whether UIColor is initialized using CIColor, CGColor or other methods, its CGColor attribute is available. CoreGraphics provides a method to determine whether two CGColors are equal, so we can judge whether two UIColors are equal. Here is a simple example:
 

Copy the codeThe code is as follows:

// judge two CGColor is equal
if (CGColorEqualToColor([UIColor whiteColor].CGColor, [UIColor colorWithRed:1 green:1 blue:1 alpha:1].CGColor)) {
    NSLog(@"The two CGColor is equal!");
}
else {
    NSLog(@"The two CGColor is not equal!");
}
   
if (CGColorEqualToColor([UIColor colorWithRed:1 green:1 blue:1 alpha:1].CGColor, [UIColor colorWithRed:1 green:1 blue:1 alpha:1].CGColor)) {
    NSLog(@"The two CGColor is equal!");
}
else {
    NSLog(@"The two CGColor is not equal!");
}

The first part in the example is to determine whether the two white UIColors are equal. Although they are both white, the color space is different. By running, we can find that "The two CGColor is not equal!" is printed. The second part of the example simply creates two RGB space UIColors, which can be seen by running the program that the two colors are the same.

Determine whether the color values ​​of the two UIColors are equal
Two days ago, a friend asked me how to determine whether the values ​​of two colors are equal. I thought it would be fine just to determine whether the RGBA values ​​of the two colors are equal soon. So I started to search for the help document and found the UIColor class, which was easy to find the function:
 

Copy the codeThe code is as follows:

- (BOOL)getRed:(CGFloat *)red green:(CGFloat *)green blue:(CGFloat *)blue alpha:(CGFloat *)alpha;

This way, you can determine whether the colors of the two UIColor objects are equal. The code is as follows:
 
Copy the codeThe code is as follows:

    enum {  
 enEqual,   
 enNotEaual,   
 enCannotConvert, 
    };
 typedef NSInteger KCompareResult;

 + (KCompareResult) isTheSameColor:(UIColor*)color 
  redValue:(CGFloat)rValue 
  greenValue:(CGFloat)gValue                                                blueValue:(CGFloat)bValue                                       
  alphaValue:(CGFloat)aValue
 {

  if ([color respondsToSelector:@selector(getRed:green:blue:alpha:)]) { 

   CGFloat redValue, greenValue, blueValue, alphaValue;
   if ([color getRed:&redValue green:&greenValue blue:&blueValue alpha:&alphaValue]) {
    if (redValue == rValue && greenValue == gValue && blueValue == bValue && alphaValue == aValue) {
     return enEqual;
    }
    else {
     return enNotEaual;
    }
   }
   else {          // can not convert  
    return enCannotConvert;
   }
  }
 }