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