NSMutableAttributedString will not display an attribute starting with a nonzero index

UPDATE:

I created a really simple standalone project showing an error. If someone wants to do the same and see if they can determine where I made a mistake, I would really appreciate it. There is not much code to view. Public repo: https://github.com/reidnez/NSAttributedStringBugDemo

I have a very strange problem: I have a table view. Each cell has a title label with 1-3 words and a keyword tag with multiple CSV keywords. I also have a search bar. The requirement is that as the user types in the search bar, any partial matches in the title and keywords for each cell are displayed highlighted. Screenshots:

Everything looks as it should searching on "Fa"

"an" highlights keyword, but not title

The first image is A-Okay. In the second image β€œa,” the title label should be highlighted. But, as you see, not so much ...

This works fine on the keywords tag, as you can see above. The attributed strings for both of these labels are created by the category I wrote (code below). The same method is called for both lines and seems to behave the same way the debugger tells me. The user interface tells a different story.

I stepped over the debugger many times, and in all cases the attribute string seemed to be configured correctly. I also confirmed that something else does not call [tableView reloadData] and that no other place in my code overwrites the label value. Here's what the β€œFang” search for β€œFang” in the debugger looks like, just before the cell returns at the end of cellForRowAtIndexPath :

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

Sounds like me ... that's exactly what I want. But when the camera shoots, there is NO glare to be seen! However, as an experiment, I tried to set the label to a completely arbitrary attributed string that I created directly in cellForRow:

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

This also fails. There is no highlighting at all ... but I CAN select any substring in the range from {0, 1} to {0, fake.length} and behave as expected. Again, he seems to refuse to allocate any substring that does not start at index 0, but only for the header label.

Am I losing my mind? What am I missing?

The following is my category ... but I'm sure that the problem is not here, because it works fine for a string with keywords, and (again) the attributes seem to be set correctly right before the cell returns:

 -(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 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. } 
+6
source share
1 answer

Thank you for writing this ... I thought I was going too!

I came up with a workaround (read: hack) while we wait for something official from Apple.

 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 

Hope this helps.

+2
source

Source: https://habr.com/ru/post/975590/


All Articles