Problem: NSAttributedString takes an NSRange while I'm using a Swift String that uses Range
let text = "Long paragraph saying something goes here!"
let textRange = text.startIndex..<text.endIndex
let attributedString = NSMutableAttributedString(string: text)
text.enumerateSubstringsInRange(textRange, options: NSStringEnumerationOptions.ByWords, { (substring, substringRange, enclosingRange, stop) -> () in
if (substring == "saying") {
attributedString.addAttribute(NSForegroundColorAttributeName, value: NSColor.redColor(), range: substringRange)
}
})
Produces the following error:
error: 'Range' is not convertible to 'NSRange' attributedString.addAttribute(NSForegroundColorAttributeName, value: NSColor.redColor(), range: substringRange)


Swift
Stringranges andNSStringranges are not "compatible". For example, an emoji like counts as one Swift character, but as twoNSStringcharacters (a so-called UTF-16 surrogate pair).Therefore your suggested solution will produce unexpected results if the string contains such characters. Example:
Output:
Long paragra{ }ph say{ NSColor = "NSCalibratedRGBColorSpace 1 0 0 1"; }ing!{ }As you see, "ph say" has been marked with the attribute, not "saying".
Since
NS(Mutable)AttributedStringultimately requires anNSStringand anNSRange, it is actually better to convert the given string toNSStringfirst. Then thesubstringRangeis anNSRangeand you don't have to convert the ranges anymore:Output:
Long paragraph { }saying{ NSColor = "NSCalibratedRGBColorSpace 1 0 0 1"; }!{ }Update for Swift 2:
Update for Swift 3:
Update for Swift 4:
As of Swift 4 (Xcode 9), the Swift standard library provides method to convert between
Range<String.Index>andNSRange. Converting toNSStringis no longer necessary:Here
substringRangeis aRange<String.Index>, and that is converted to the correspondingNSRangewith