NSAttributedString颜色测试

比较或测试NSAttributed字符串的特定颜色属性的正确方法是什么?

作为一个例子,我想知道文本选择是否有红色文本。 我已经尝试了几种方法,如下所示,但它们都没有产生匹配。 我看到文本在屏幕上变为红色,并且记录该属性返回: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; } 

以下是我为测试传递属性的方法:

 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]; } } 

我认为这不重要,但为了完整起见,我将文本设置为红色。

 NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithAttributedString:self.synopsisTextView.attributedText]; [attributedString addAttribute:NSForegroundColorAttributeName value:[UIColor redColor] range:selectedRange]; self.synopsisTextView.attributedText = attributedString; 

Objective-C是C的严格超集。Objective-C对象存在于堆上并且跟踪via指针。 这样的净效果就是测试:

 [attributes objectForKey:NSForegroundColorAttributeName] == [UIColor colorWithRed:1 green:0 blue:0 alpha:1] 

测试身份而不是平等。 也就是说,不是测试两个对象是否具有相同的值,而是测试它们是否是相同的物理对象,并且位于内存中的相同地址。 C不允许运算符重载,因此==运算符在Objective-C中的含义与C中的含义完全相同。您将比较两个指针。 他们碰巧指向Objective-C对象既不在这里也不在那里。

你可能想要:

 [[attributes objectForKey:NSForegroundColorAttributeName] isEqual: [UIColor colorWithRed:1 green:0 blue:0 alpha:1]] 

这将允许UIColor对象应用它认为将建立相等性的任何测试。

唯一可能的警告是, UIColor只有在相对于相同颜色空间定义并具有相同系数时才认为颜色相等。 假设你总是在RGBA中定义所有颜色,这些颜色应该没有什么区别。

尝试在属性dict中测试NSForegroundColorAttributeName对象而不是NSFontAttributeName如下所示:

 NSAttributedString *selectedString = [attributedString attributedSubstringFromRange:selectedRange]; [selectedString enumerateAttributesInRange:NSMakeRange(0, [selectedString length]) options:NSAttributedStringEnumerationLongestEffectiveRangeNotRequired usingBlock:^(NSDictionary *attributes, NSRange range, BOOL *stop) { UIColor *fgColor = [attributes objectForKey:NSForegroundColorAttributeName]; if ([fgColor isEqual:[UIColor redColor]]) { NSLog(@"detected red. set selected"); [self.redButton setSelected:YES]; } else { NSLog(@"detected not red. do not set selected"); [self.redButton setSelected:NO]; } } 

您必须创建一个-isEqualToColor:方法进行比较。 UIColor只从NSObjectinheritance-isEqual:如果它们的哈希值相等,则会看到两个UIColor实例相等。

这样的方法相当容易构造,只需获得与颜色空间无关的RGB + A值,如果所有这些值都相同,则颜色相等。

如果你很懒,你会使用CGColorEqualToColor但是如果一个是灰色(2个组件)而另一个是RGBA颜色(4个组件)则不报告相等。

这可能就是为什么Apple没有实现-isEqualToColor:方法的原因,因为如果组件的数量应该起作用或者它是否只是RGB值,意见会大不相同。 因此,我建议您找到自己的定义并相应地实施比较。

PS:在某些情况下你可能会发现isEqual工作,因为UIColor会保留一些标准颜色的缓存,例如,如果你请求红色,那么你将获得相同的实例。 相同的实例意味着相同的散列,因此“相等”。 但正如我之前所说,依靠实施并不是一件好事。