Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

NSAttributedString Color Test

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;
like image 568
DenVog Avatar asked Dec 06 '12 19:12

DenVog


People also ask

What is an NSAttributedString?

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.

What is NSMutableAttributedString?

A mutable string with associated attributes (such as visual style, hyperlinks, or accessibility data) for portions of its text.


1 Answers

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.

like image 198
Tommy Avatar answered Sep 22 '22 19:09

Tommy