NSMutableAttributedString不会显示以非零索引开头的属性

Rei*_*eid 6 uitableview ios nsmutableattributedstring

更新:

我创建了一个非常简单的独立项目来演示这个bug.如果有人想拉同样的,看看他们是否能找到我出错的地方,我一定会很感激.没有太多代码可供查看.公共回购:https: //github.com/reidnez/NSAttributedStringBugDemo

我在这里遇到一个非常奇怪的问题:我有一个桌面视图.每个单元格都有一个1-3个单词的标题标签,以及一个包含多个CSV关键字的关键字标签.我也有一个搜索栏.要求是当用户键入搜索栏时,每个单元格的标题和关键字的任何部分匹配都会突出显示.截图:

一切看起来应该搜索

第一张图片是A-Okay.在第二个图像中,应突出显示标题标签的"an".但是,正如你所看到的,不是那么多......

这可以在"关键字"标签上完美地运行,如上所示.这两个标签的属性字符串都是由我写的类别(下面的代码)创建的.在两个字符串上调用相同的方法,并且看起来与调试器告诉我的行为相同.UI讲述了一个不同的故事.

我已多次遍历调试器,并且在所有情况下,属性字符串似乎已正确配置.我还验证了其他东西没有调用[tableView reloadData],我的代码中没有其他地方覆盖标签的值.这就是"方"的"an"匹配在调试器中的位置,就在单元格返回结束之前cellForRowAtIndexPath:

(lldb) po customCell.entryTitleLabel.attributedText
F{
}an{
NSBackgroundColor = "UIDeviceRGBColorSpace 0.533333 0.835294 0.156863 1";
}g{
}
Run Code Online (Sandbox Code Playgroud)

对我来说很好......这正是我想要的.但是当细胞渲染时,没有任何亮点可见!更奇怪的是,作为一个实验,我尝试将标签设置为我在cellForRow中创建的完全任意的attributesString:

NSMutableAttributedString *fake = [[NSMutableAttributedString alloc] initWithString:@"Fang"];
            [fake addAttribute:NSBackgroundColorAttributeName value:MATCH_TEXT_HILIGHT_COLOR range:NSMakeRange(1, 2)];
            customCell.entryTitleLabel.attributedText = fake;
Run Code Online (Sandbox Code Playgroud)

这也失败了.根本没有突出显示...但我可以突出显示{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.
}
Run Code Online (Sandbox Code Playgroud)

小智 2

感谢您写下这篇文章...我以为我也疯了!

在我们等待苹果官方发布消息的同时,我想出了一个解决方法(阅读:破解)。

NSDictionary *hackAttribute = [NSDictionary dictionaryWithObjectsAndKeys:
                           [UIColor clearColor], NSBackgroundColorAttributeName, nil];

NSMutableAttributedString *attributedText =
    [[NSMutableAttributedString alloc] initWithString:@"some text..."];
    [attributedAddressText setAttributes:hackAttribute range:NSMakeRange(0, attributedText.length)];
// Then set your other attributes as per normal
Run Code Online (Sandbox Code Playgroud)

希望有帮助。