8

NSAttributed文字列の特定の色属性を比較またはテストする正しい方法は何ですか?

例として、テキスト選択に赤いテキストがあるかどうかを知りたいです。以下に示すように、私はいくつかのアプローチを試しましたが、どれも一致することはありません。画面上でテキストが赤くなり、属性をログに記録すると、UIDeviceRGBColorSpace 1 001が返されます。

- (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;
4

3 に答える 3

9

Objective-C は C の厳密なスーパーセットです。Objective-C オブジェクトはヒープ上に存在し、ポインターを介して追跡されます。これの正味の効果は、テストが次のようになることです。

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

平等ではなく同一性をテストします。つまり、2 つのオブジェクトが同じ値を持っているかどうかをテストするのではなく、メモリ内の同じアドレスにある同じ物理オブジェクトであるかどうかをテストしています。C では演算子のオーバーロードが許可されていないため==、Objective-C でも演算子は C とまったく同じ意味を持ちます。2 つのポインターを比較しています。彼らがたまたまObjective-Cオブジェクトを指しているということは、ここにもありません。

あなたはおそらく欲しい:

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

これにより、UIColorオブジェクトは、同等性を確立すると見なすテストを適用できます。

唯一の潜在的な注意点は、UIColor色が同じ色空間に対して相対的に定義され、同じ係数を持つ場合にのみ、色が等しいと見なされることです。RGBA で常にすべての色を定義していると仮定すると、違いはありません。

于 2012-12-07T02:04:01.263 に答える
5

次のよう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];
    }
}
于 2012-12-07T02:07:21.343 に答える
0

-isEqualToColor:比較のためのメソッドを作成する必要があります。UIColor は NSObject からのみ継承し-isEqual:、ハッシュが等しい場合、これは UIColor の 2 つのインスタンスを等しいと見なします。

このような方法は非常に簡単に作成できます。色空間に関係なく RGB+A 値を取得するだけで、これらの値がすべて同じであれば色は等しくなります。

怠惰な人は使用しますCGColorEqualToColorが、一方がグレー色 (2 コンポーネント) であり、もう一方が RGBA カラー (4 コンポーネント) である場合、同等であるとは報告されません。

これはおそらく、-isEqualToColor:コンポーネントの数が役割を果たすべきか、RGB 値のみであるかどうかについて意見が大きく異なるため、Apple がメソッドを実装していない理由です。したがって、独自の定義を見つけて、それに応じて比較を実装することをお勧めします。

PS: UIColor はいくつかの標準色のキャッシュを保持しているため、場合によっては isEqual が機能していることに気付くかもしれません。たとえば、赤をリクエストすると、同じインスタンスが取得されます。同じインスタンスは同じハッシュを意味するため、「等しい」。しかし、前に言ったように、実装に依存するのは良いスタイルではありません。

于 2012-12-21T19:21:37.773 に答える