More Swifty NSAttributedString Attribute Query Methods
NSAttributedString
API takes an NSRange
by-reference. That’s cumbersome to use, though, because you need to initialize a non-nil range, and there you should initialize it with NSNotFound
to indicate an illegal state. Afterwards, you need to check if the range changed to a legal value.
A more Swift-y approach is to use tuples:
extension NSAttributedString {
/// Wrapper for `attribute(_:at:effectiveRange:)` returning value and range.
/// - Returns: Tuple of the attribute value and effective range in which
/// `attributeName` applies around `location`. `nil` if no match is found or
/// the range lookup failed.
func attribute(_ attributeName: NSAttributedString.Key,
at location: Int
) -> (value: Any, effectiveRange: NSRange)? {
var range: NSRange = NSRange(location: NSNotFound, length: 0)
guard let value = attribute(attributeName, at: location, effectiveRange: &range),
range.location != NSNotFound
else { return nil }
return (value, range)
}
/// Wrapper for the range result of `attribute(_:at:effectiveRange:)`.
/// - Returns: Effective range in which `attributeName` applies
// around `location`. `nil` if no match is found.
func effectiveAttributeRange(attributeName: NSAttributedString.Key,
at location: Int) -> NSRange? {
return attribute(attributeName, at: location)?.range
}
}
This is hardly mind-blowing, but I lived without this for 5 years or so and now I’m fed up. :) Might as well share the result, right?