What is the correct way to compare, or test, for a particular color attribute of an NSAttributed string?
As an example, I'd like to know if the text selection has red text. I have tried several approaches, as you can see below, but none of them ever results in a match. I see the text turn red on screen, and logging the attribute returns: UIDeviceRGBColorSpace 1 0 0 1
- (BOOL)isRedWithAttributes:(NSDictionary *)attributes
{
BOOL isRedWithAttributes = NO;
if (attributes != nil)
{
// if ( [attributes objectForKey:NSForegroundColorAttributeName] == [UIColor redColor] )
// if ( [attributes objectForKey:NSForegroundColorAttributeName] == @"UIDeviceRGBColorSpace 1 0 0 1" )
if ( [attributes objectForKey:NSForegroundColorAttributeName] == [UIColor colorWithRed:1 green:0 blue:0 alpha:1] )
{
isRedWithAttributes = YES;
}
else
{
isRedWithAttributes = NO;
}
}
return isRedWithAttributes;
}
Here is how I pass the attribute for the test:
NSAttributedString *selectedString = [attributedString attributedSubstringFromRange:selectedRange];
[selectedString enumerateAttributesInRange:NSMakeRange(0, [selectedString length])
options:NSAttributedStringEnumerationLongestEffectiveRangeNotRequired
usingBlock:^(NSDictionary *attributes, NSRange range, BOOL *stop)
{
UIFont *fontFace = [attributes objectForKey:NSFontAttributeName];
BOOL isRedWithAttributes = [fontFace isRedWithAttributes:attributes];
if (isRedWithAttributes)
{
NSLog(@"detected red. set selected");
[self.redButton setSelected:YES];
}
else
{
NSLog(@"detected not red. do not set selected");
[self.redButton setSelected:NO];
}
}
I don't think it matters, but for completeness, here is how I set the text to be red.
NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithAttributedString:self.synopsisTextView.attributedText];
[attributedString addAttribute:NSForegroundColorAttributeName value:[UIColor redColor] range:selectedRange];
self.synopsisTextView.attributedText = attributedString;
An NSAttributedString object manages character strings and associated sets of attributes (for example, font and kerning) that apply to individual characters or ranges of characters in the string. An association of characters and their attributes is called an attributed string.
A mutable string with associated attributes (such as visual style, hyperlinks, or accessibility data) for portions of its text.
Objective-C is a strict superset of C. Objective-C objects live on the heap and are kept track of via pointer. The net effect of this is that the test:
[attributes objectForKey:NSForegroundColorAttributeName] ==
[UIColor colorWithRed:1 green:0 blue:0 alpha:1]
tests identity rather than equality. That is, rather than testing whether two objects have the same value you're testing whether they're the same physical object, sitting at the same address in memory. C doesn't allow operator overloading so the ==
operator has exactly the same meaning in Objective-C as in C. You're comparing two pointers. That they happen to point to Objective-C objects is neither here nor there.
You probably want:
[[attributes objectForKey:NSForegroundColorAttributeName] isEqual:
[UIColor colorWithRed:1 green:0 blue:0 alpha:1]]
Which will allow the UIColor
object to apply whatever test it considers will establish equality.
The only potential caveat is that UIColor
considers colours to be equal only if they're defined relative to the same colour space and have the same coefficients. Assuming you're always defining all your colours in RGBA that shouldn't make a difference.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With