How can I convert a UITextRange object to an NSRange? I've seen plenty of SO posts about going the other direction but that's the opposite of what I need. I'm using the UITextRange selectedTextRange which is a property of a UITextView. It returns a UITextRange but I need a range.
4 Answers
You need something like this:
- (NSRange) selectedRangeInTextView:(UITextView*)textView { UITextPosition* beginning = textView.beginningOfDocument; UITextRange* selectedRange = textView.selectedTextRange; UITextPosition* selectionStart = selectedRange.start; UITextPosition* selectionEnd = selectedRange.end; const NSInteger location = [textView offsetFromPosition:beginning toPosition:selectionStart]; const NSInteger length = [textView offsetFromPosition:selectionStart toPosition:selectionEnd]; return NSMakeRange(location, length); } Comments
Here's a Swift extension based on the answer by Vitaly S.
extension UITextInput { var selectedRange: NSRange? { guard let range = self.selectedTextRange else { return nil } let location = offsetFromPosition(beginningOfDocument, toPosition: range.start) let length = offsetFromPosition(range.start, toPosition: range.end) return NSRange(location: location, length: length) } } Swift 4
extension UITextInput { var selectedRange: NSRange? { guard let range = selectedTextRange else { return nil } let location = offset(from: beginningOfDocument, to: range.start) let length = offset(from: range.start, to: range.end) return NSRange(location: location, length: length) } } Comments
UITextView has a property
@property(nonatomic) NSRange selectedRange; 3 Comments
Stunner
This doesn't answer the OP's question. There are valid reasons why you need to convert from
UITextRange to NSRange.Daniel Klöck
Also, it doesn't exist in swift
Leslie Godwin
Also, UITextField only has
selectedTextRange, so you need convert to a simple NSRangeSwift 5
extension UITextInput { var selectedRange: NSRange? { if let selectedRange = self.selectedTextRange { return NSMakeRange(self.offset(from: self.beginningOfDocument, to: selectedRange.start), self.offset(from: selectedRange.start, to: selectedRange.end)) } else { return nil } } } 1 Comment
kwiknik
Your code will be cleaner if you begin with
guard let.. else { return nil } instead of the way you've written it.