In the NSAttributedString class, there are functions that get the values of attributes for certain indices and ranges but I'm unsure of the difference between the selectors attributesAtIndex:effectiveRange and attributesAtIndex:longestEffectiveRange:inRange: and when would I use one instead of the other? Thanks in advance for any clarification
Let's say you have this kind of attributes:
Range [0,2]: Black Background Color
Range [0,2]: Bold Font
Range [2,4]: Black Background Color
Range [2,4]: Italic Font
If you log this NSAttributedString, its attributes will be separated in two:
Range [0,2]: Black Background Color AND Bold Font
Range [2,4]: Black Background Color AND Italic Font
These attributes works like a NSDictionary, they are 2 different at two ranges.
If you use longestEffectiveRange at index 0 for NSBackgroundColorAttributeName, you'll get a range of [0,4].
If you use effectiveRange, you'll get [0,2].
In other words, the longestEffectiveRange will check if there is on the next index (after the end of effectiveRange) that may have another dictionary of attributes if it shares the wanted value with it and then append the range.
Sample Code:
NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithString:@"BoBiBu"];
[attributedString addAttribute:NSBackgroundColorAttributeName
value:[UIColor blackColor]
range:NSMakeRange(0, 2)];
[attributedString addAttribute:NSFontAttributeName
value:[UIFont boldSystemFontOfSize:12]
range:NSMakeRange(0, 2)];
[attributedString addAttribute:NSFontAttributeName
value:[UIFont italicSystemFontOfSize:12]
range:NSMakeRange(2, 2)];
[attributedString addAttribute:NSBackgroundColorAttributeName
value:[UIColor blackColor]
range:NSMakeRange(2, 2)];
NSLog(@"AttributedString: %@", attributedString);
NSRange range1;
NSLog(@"Attribute: %@", [attributedString attribute:NSBackgroundColorAttributeName atIndex:0 effectiveRange:&range1]);
NSLog(@"EffectiveRange of previous attribute: %@", NSStringFromRange(range1));
NSRange range2;
NSLog(@"Attribute: %@", [attributedString attribute:NSBackgroundColorAttributeName atIndex:0 longestEffectiveRange:&range2 inRange:NSMakeRange(0, 6)]);
NSLog(@"Longest effective Range of previous attribute: %@", NSStringFromRange(range2));
Logs:
> AttributedString: Bo{
NSBackgroundColor = "UIDeviceWhiteColorSpace 0 1";
NSFont = "<UICTFont: 0x7fd3e2f80ec0> font-family: \".HelveticaNeueInterface-MediumP4\"; font-weight: bold; font-style: normal; font-size: 12.00pt";
}Bi{
NSBackgroundColor = "UIDeviceWhiteColorSpace 0 1";
NSFont = "<UICTFont: 0x7fd3e2f83310> font-family: \".HelveticaNeueInterface-Italic\"; font-weight: normal; font-style: italic; font-size: 12.00pt";
}Bu{
}
> Attribute: UIDeviceWhiteColorSpace 0 1
> EffectiveRange of previous attribute: {0, 2}
> Attribute: UIDeviceWhiteColorSpace 0 1
> Longest effective Range of previous attribute: {0, 4}
I wrote a test for complementing the best answer.
// In UnitTest target.
func testLongestEffectiveRange() throws {
let textStorage = NSTextStorage(string: "abcd")
textStorage.addAttributes([.backgroundColor: UIColor.red, .font: UIFont.boldSystemFont(ofSize: 17)], range: NSRange(location: 0, length: 2))
textStorage.addAttributes([.backgroundColor: UIColor.red, .font: UIFont.italicSystemFont(ofSize: 17)], range: NSRange(location: 2, length: 2))
var effectiveColorRange: NSRange? = NSRange(location: 0, length: 0)
let effectiveColor = textStorage.attribute(.backgroundColor, at: 0, effectiveRange: &effectiveColorRange!)
XCTAssertEqual(effectiveColorRange, NSRange(location: 0, length: 2))
XCTAssertEqual((effectiveColor as? UIColor), UIColor.red)
var effectiveFontRange: NSRange? = NSRange(location: 0, length: 0)
let effectiveFont = textStorage.attribute(.font, at: 0, effectiveRange: &effectiveFontRange!)
XCTAssertEqual(effectiveFontRange, NSRange(location: 0, length: 2))
XCTAssertEqual((effectiveFont as? UIFont), UIFont.boldSystemFont(ofSize: 17))
var longestEffectiveColorRange: NSRange? = NSRange(location: 0, length: 0)
let longestEffectiveColor = textStorage.attribute(.backgroundColor, at: 2, longestEffectiveRange: &longestEffectiveColorRange!, in: NSRange(location: 0, length: textStorage.string.utf16.count))
// longestEffectiveRange returns the longest possible range for the attribute.
XCTAssertEqual(longestEffectiveColorRange, NSRange(location: 0, length: 4))
XCTAssertEqual((longestEffectiveColor as? UIColor), UIColor.red)
var longestEffectiveFontRange: NSRange? = NSRange(location: 0, length: 0)
let longestEffectiveFont = textStorage.attribute(.font, at: 2, effectiveRange: &longestEffectiveFontRange!)
XCTAssertEqual(longestEffectiveFontRange, NSRange(location: 2, length: 2))
XCTAssertEqual((longestEffectiveFont as? UIFont), UIFont.italicSystemFont(ofSize: 17))
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With