NSRange from Swift Range?
Master System Design with Codemia
Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.
Introduction
Swift strings use Range<String.Index> while many Foundation and Objective-C APIs use NSRange. Converting between them is common in iOS development, but the conversion must always be tied to the specific string involved.
The safe rule is simple: let Foundation do the conversion for you. Manual integer math is fragile because Swift strings are Unicode-aware and do not map cleanly to visible-character counts.
If you stay on the official conversion APIs, most of the tricky Unicode edge cases disappear from your application code.
Convert a Swift Range to NSRange
If you already have a native Swift range, convert it like this:
That initializer understands the string's UTF-16 representation, which is what Foundation APIs expect.
Convert NSRange Back to a Swift Range
When a Foundation API gives you an NSRange, convert it back with the failable Range initializer:
The initializer can fail because not every NSRange is valid for every Swift string. That is a feature, not a nuisance.
Why Manual Offsets Are Dangerous
Swift strings are collections of extended grapheme clusters. Foundation ranges are usually expressed in UTF-16 code units. Those are not always the same thing.
For example:
Those numbers can differ. If you build an NSRange from String.count, it may be wrong for emoji, accented characters, or composed Unicode sequences.
Use the Right Range Type for the Right API
Stay in native Swift ranges as long as you are slicing or searching Swift strings. Convert only when an Objective-C or Foundation API requires NSRange.
NSRegularExpression is a common example:
This pattern is safe and common: create the full-string NSRange, call the Foundation API, then convert the returned range back into Swift form.
That keeps the Foundation boundary narrow and lets the rest of your code stay in native Swift string types.
Remember That the String Matters
An NSRange is not meaningful by itself. It only means something relative to the exact string it was created from. If the string changes, the range may no longer point to the same text or may become invalid.
That means you should not cache an NSRange and reuse it after editing the underlying string. Recompute the range from the current text instead.
Common Pitfalls
- Building an
NSRangemanually from integer counts. - Assuming
String.countandNSString.lengthmeasure the same thing. - Forgetting that
Range(nsRange, in: string)can fail. - Reusing an
NSRangeafter the source string has changed. - Staying in
NSRangelonger than necessary instead of converting back to a Swift range for Swift string work.
Summary
- Use
NSRange(swiftRange, in: string)to convert from Swift range toNSRange. - Use
Range(nsRange, in: string)to convert back safely. - Avoid manual offset math because Swift strings are Unicode-aware.
- Keep
NSRangeat Foundation boundaries and prefer Swift ranges elsewhere. - Treat every range as valid only for the specific string it came from.

