Welcome to the wild and woolen world of wide color and color management.
Your two colors are not equal, for isEqual (or Swift == , which goes through isEqual for the ObjC classes that have it), because they have different color spaces. (They are not different classes, the first element in UIColor.description is the identifier of the color space or where the color space does not have a name, the model for the color space - that is, whether it is based on RGB, CMYK, grayscale, etc.)
Without the color space to determine their color, the four values ββof the color component do not have a reliable value, so isEqual uses both the component values ββand the color space to check for equality.
Beyond Color Spaces (skip down for solutions)
Your color created using UIColor init(red:green:blue:alpha:) uses the "Extended sRGB" color space. This color space is designed to support wide color displays (for example, the P3 color display on the iPhone 7, iPad Pro 9.7 ", iMac at the end of 2015, the MacBook Pro at the end of 2016, and maybe something else will come next), but are compatible with components with sRGB color space used on other devices.
For example, sRGB 1.0, 0.0, 0.0 is the βredβ that you probably use most often ... but if you create a color in the P3 color space with RGB 1.0, 0.0, 0.0 , you will get a lot more. If you have an application in which you need to support sRGB and P3 displays and work directly with color components, this can be confusing. Thus, the Extended sRGB space allows the same component values ββto mean the same thing, but also allows you to specify colors outside the sRGB gamut, using values ββoutside the range 0.0 - 1.0 . For example, the 1.093, -0.227, -0.15 Display P3 can display is expressed in Extended sRGB as (approximately) 1.093, -0.227, -0.15 .
Like [docs for this initializer note, for applications related to iOS 10 or later SDK, init(red:green:blue:alpha:) creates color in the extended sRGB color space, but for older applications (even if they work on iOS 10), it creates color in a device-defined RGB space (which can usually be considered equivalent to sRGB).
Work with different color spaces
So, either your color replacement code or some code creates colors in your attribute string, you need to know the color spaces. There are several possible ways to deal with this; Choose the one that best suits you:
Make sure that your line creation code and color swap code use the same device-independent color space. UIColor does not provide many utilities for working with color spaces, so you can use Display P3 (on iOS 10 and above) or CGColor down to CGColor :
let sRGB = CGColorSpace(name: CGColorSpace.sRGB)! let cgDarkRed = CGColor(colorSpace: sRGB, components: [0.666667, 0.172549, 0.172549, 1])! let darkRed = UIColor(cgColor: cgDarkRed) // example creating attributed string... let attrString = NSAttributedString(string: "red", attributes: [NSForegroundColorAttributeName : darkRed]) // example processing text... let redAttributes = [NSForegroundColorAttributeName: darkRed] text.enumerateAttributes(in: NSRange(0..<attrString.length)) { (attributes, range, stop) in for (_, textColor) in attributes where (textColor as? UIColor) != darkRed { text.setAttributes(redAttributes , range: range) } }
If you cannot control the input colors, convert them to the same color space before comparison. Here is the UIColor extension for this:
extension UIColor { func isEqualWithConversion(_ color: UIColor) -> Bool { guard let space = self.cgColor.colorSpace else { return false } guard let converted = color.cgColor.converted(to: space, intent: .absoluteColorimetric, options: nil) else { return false } return self.cgColor == converted } }
(Then you can simply use this function instead of == or isEqual in your text processing.)
Just get the values ββof the original color components and compare them directly based on the assumption that you know that the color spaces are compatible for both. Relatively fragile, so I recommend against this option.