alexis

software engineer, nyc

Byte of the Week: String Range & NSRange

In Swift, a character of a String cannot be accessed by its integer position. You need to use a more complex index type that takes Unicode character representation into account. This index type is not compatible with NSRange, which is used by a lot of Objective-C APIs.

The good news is that the Swift Standard Library provides little-known type-safe helpers to convert a String index range to an NSRange and vice-versa:

  • Use NSRange(_:in:) to convert a String range to an NSRange. The first argument is the range, and the second is the string you created the range from.
  • Use Range<String.Index>(_:in:) to convert an NSRange to a Swift range. The first argument is the NSRange, and the second one is the string you want to use the range with. If the NSRange is not valid for that String, the initializer returns nil.

Example

// 1) Create a range in Swift
let string = "Hello World 🧑🏼‍💻"
let plainTextRange = string.startIndex
    ..< string.index(string.endIndex, offsetBy: -2)

// 2) Create an NSRange from the String range
let nsRange = NSRange(plainTextRange, in: string)
print((string as NSString).substring(with: nsRange)) // prints "Hello World"

// 3) Convert it back to a String range
if let convertedRange = Range<String.Index>(nsRange, in: string) {
    print(string[convertedRange]) // prints "Hello World"
}