比较或测试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对象位于堆上,并通过指针跟踪。这样做的净效果是测试:
[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只从NSObject继承了一个-isEqual:
,如果两个UIColor实例的哈希值相等,则这两个实例是相等的。
这样的方法很容易构建,只需获得独立于颜色空间的RGB+a值,如果所有这些值都相同,则颜色是相等的。
如果你很懒,你会使用CGColorEqualToColor
,但如果一个是灰色(2个分量),而另一个是RGBA颜色(4个分量)的话,则不会报告相等。
这可能是苹果没有实施-isEqualToColor:
方法的原因,因为如果组件的数量应该发挥作用,或者仅仅是RGB值,人们的意见会大相径庭。因此,我建议您找到自己的定义,并相应地进行比较。
PS:在某些情况下,你可能会发现isEqual有效,因为UIColor保留了一些标准颜色的缓存,如果你请求红色,那么你会得到相同的实例。相同的实例意味着相同的散列,因此"相等"。但正如我之前所说,依赖于实现并不是一个好的风格