EffectiveRange 和 LongestEffectiveRange 之间的区别

Difference Between EffectiveRange and LongestEffectiveRange

NSAttributedString class 中,有些函数可以获取某些索引和范围的属性值,但我不确定选择器 attributesAtIndex:effectiveRangeattributesAtIndex:longestEffectiveRange:inRange: 什么时候我会用一个而不是另一个?预先感谢任何澄清

假设你有这样的属性:
范围 [0,2]:黑色背景色
范围 [0,2]:粗体字体
范围 [2,4]:黑色背景颜色
范围 [2,4]:斜体字体

如果你记录这个NSAttributedString,它的属性将被分成两部分:
范围 [0,2]:黑色背景颜色和粗体字体
范围 [2,4]:黑色背景颜色和斜体字体
这些属性的作用类似于 NSDictionary,它们在两个范围内有 2 个不同。

如果您在 NSBackgroundColorAttributeName 的索引 0 处使用 longestEffectiveRange,您将得到 [0,4] 的范围。
如果你使用 effectiveRange,你会得到 [0,2].
换句话说,longestEffectiveRange 将检查下一个索引(在 effectiveRange 结束后)是否有另一个属性字典,如果它与它共享想要的值,然后附加范围.

示例代码:

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));

日志:

> 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}

我写了一个测试来补充最佳答案。


// 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))

}