アップデート:
バグを示すために、非常に単純なスタンドアロン プロジェクトを作成しました。誰かが同じことを引っ張って、私が間違っていた場所を見つけられるかどうかを確認したい場合は、それを感謝します. 調べるコードはあまりありません。ここの公開リポジトリ: https://github.com/reidnez/NSAttributedStringBugDemo
ここで非常に奇妙な問題が発生しています。テーブルビューがあります。各セルには、1 ~ 3 語のタイトルラベルと、複数の CSV キーワードを含むキーワードラベルがあります。検索バーもあります。要件は、ユーザーが検索バーに入力すると、各セルのタイトルとキーワードの両方で部分一致が強調表示されることです。スクリーンショット:
最初の画像はA-OKです。2 番目の画像では、タイトル ラベルの「an」が強調表示されている必要があります。しかし、ご覧のとおり、それほど多くはありません...
上記のように、これは「キーワード」ラベルで完全に機能します。これら両方のラベルの属性文字列は、私が書いたカテゴリによって作成されます (以下のコード)。同じメソッドが両方の文字列で呼び出され、デバッガーが私に伝えていることから、同じように動作するように見えます。UI は別の話をします。
デバッガーを何度も実行しましたが、いずれの場合も、属性付きの文字列は正しく構成されているようです。また、他の何かが呼び出さ[tableView reloadData]
れていないこと、およびコード内の他の場所でラベルの値が上書きされていないことも確認しました。これは、セルが の最後に返される直前に、"Fang" の "an" でのマッチングがデバッガーでどのように見えるかを示していますcellForRowAtIndexPath
。
(lldb) po customCell.entryTitleLabel.attributedText
F{
}an{
NSBackgroundColor = "UIDeviceRGBColorSpace 0.533333 0.835294 0.156863 1";
}g{
}
私には良さそうです...それはまさに私が欲しいものです。しかし、セルがレンダリングされると、見られるハイライトはありません! さらに奇妙なことに、実験として、cellForRow で作成した完全に任意の attributedString にラベルを設定してみました。
NSMutableAttributedString *fake = [[NSMutableAttributedString alloc] initWithString:@"Fang"];
[fake addAttribute:NSBackgroundColorAttributeName value:MATCH_TEXT_HILIGHT_COLOR range:NSMakeRange(1, 2)];
customCell.entryTitleLabel.attributedText = fake;
これも失敗。強調表示はまったくありません...しかし、{0, 1} から {0, fake.length} の範囲の部分文字列を強調表示でき、期待どおりに動作します。繰り返しますが、インデックス 0 で始まらない部分文字列を強調表示することを拒否しているように見えますが、タイトル ラベルのみです。
私は私の心を失っていますか?私は何が欠けていますか?
以下は私のカテゴリです...しかし、キーワード文字列に対して完全に機能し、セルが戻る直前に属性が正しく設定されているように見えるため、問題はここにないと確信しています。
-(void)hilightMatchingSubstring:(NSString*)substring color:(UIColor*)hilightColor range:(NSRange)range
{
if ([self.string compare:substring options:NSCaseInsensitiveSearch] == NSOrderedSame) {
[self addAttribute:NSBackgroundColorAttributeName value:hilightColor range:NSMakeRange(0, self.length)];
return;
}
// Sanity check. Make sure a valid range has been passed so that we don't get out-of-bounds crashes. Default to return self wrapped in an attributed string with no attributes.
NSRange selfRange = NSMakeRange(0, self.length);
if (NSIntersectionRange(selfRange, range).length == 0) {
NSLog(@" \n\n\n*** Match range {%lu, %lu} does not intersect main string's range {%lu, %lu}. Aborting *** \n\n\n", (unsigned long)range.location, (unsigned long)range.length, (unsigned long)selfRange.location, (unsigned long)selfRange.length);
return;
}
if (substring.length > 0) {
NSRange movingRange = NSMakeRange(range.location, substring.length);
if (NSMaxRange(movingRange) > self.length) {
return;
}
NSString *movingString = [self.string substringWithRange:movingRange];
while (NSMaxRange(movingRange) < NSMaxRange(range)) {
if ([movingString compare:substring options:NSCaseInsensitiveSearch] == NSOrderedSame) {
[self addAttribute:NSBackgroundColorAttributeName value:hilightColor range:movingRange];
}
movingRange = NSMakeRange(movingRange.location + 1, substring.length);
movingString = [self.string substringWithRange:movingRange];
}
} // This is fine...string leaves properly attributed.
}