4

I have extension for UITextView:

extension UITextView {

    func separatedWordsInFrontCursor(infront: Bool = true) -> [String] {

        let cursorPosition = selectedRange.location
        let separationCharacters = NSCharacterSet(charactersInString: " ")

        let beginRange = Range(start: text.startIndex.advancedBy(0), end: text.startIndex.advancedBy(cursorPosition))
        //fatal error: can not increment endIndex

        let endRange = Range(start: text.startIndex.advancedBy(cursorPosition), end: text.startIndex.advancedBy(text.characters.count))

        let beginPhrase = text.substringWithRange(beginRange)
        let endPhrase = text.substringWithRange(endRange)

        return infront ? beginPhrase.componentsSeparatedByCharactersInSet(separationCharacters) : endPhrase.componentsSeparatedByCharactersInSet(separationCharacters)
    }
}

Error is following:

fatal error: can not increment endIndex

This is what I try to type into UITextView:enter image description here

Keyboard type for UITextView is set to Default.

When error arise:

cursorPosition is 3
text.characters.count is 2
text.startIndex is 0
text.startIndex.advancedBy(2) is 3
text.startIndex.advancedBy(cursorPosition) is "fatal error: can not increment endIndex"

How can I workaround this?

Bartłomiej Semańczyk
  • 59,234
  • 49
  • 233
  • 358
  • 3
    The problem is that String ranges and NSString ranges are different and "incompatible". Have a look at http://stackoverflow.com/questions/25138339/nsrange-to-rangestring-index and its various solutions. Another similar problem is this: http://stackoverflow.com/questions/27040924/nsrange-from-swift-range. – Martin R Jan 05 '16 at 12:26
  • Try this:let endRange = Range(start: text.startIndex.advancedBy(cursorPosition), end: text.endIndex) – Lumialxk Jan 05 '16 at 12:27
  • @Lumialxk fatal error belongs to line with `beginRange`. – Bartłomiej Semańczyk Jan 05 '16 at 12:29
  • @MartinR you are right, but the answers are not related to problem with `selectedRange.location` of `UITextView`. This is the base for my code. – Bartłomiej Semańczyk Jan 05 '16 at 13:03
  • I am quite sure that it is the same problem with the same possible solutions. `selectedRange` is an `NSRange`, but `text` is a (Swift) `String`. Converting that to an NSString (as in the accepted answer to the first thread) and then operate on NSStrings only could be the easiest solution. If you want to convert from NSRange to a `Range` then have a look at http://stackoverflow.com/a/30404532/1187415. – Martin R Jan 05 '16 at 13:07
  • @MartinR I changed code to `text.utf16.startIndex`... but then `substringToIndex` throws an error: `Cannot convert String.UTF16View.Index to String.CharactersView.Index` – Bartłomiej Semańczyk Jan 05 '16 at 13:08
  • There was an error,I updated my answer. – Lumialxk Jan 06 '16 at 03:13

1 Answers1

1

As @Martin R said we need to operate on NSRange and NSString, so the solution is following:

private func separatedWordsInFrontCursor(infront: Bool = true) -> [String] {

    let cursorPosition = selectedRange.location
    let separationCharacters = NSCharacterSet(charactersInString: " ")

    let nstext = NSString(string: text)

    let beginRange = NSRange(location: 0, length: cursorPosition)
    let endRange = NSRange(location: cursorPosition, length: nstext.length - cursorPosition)

    let beginPhrase = nstext.substringWithRange(beginRange)
    let endPhrase = nstext.substringWithRange(endRange)

    return infront ? beginPhrase.componentsSeparatedByCharactersInSet(separationCharacters) : endPhrase.componentsSeparatedByCharactersInSet(separationCharacters)
}
Bartłomiej Semańczyk
  • 59,234
  • 49
  • 233
  • 358
  • I found the reason why you got this.Because text.startIndex.advanceBy() returns a wrong value with emoji.I will post my codes tomorrow,now I'm so sleepy. – Lumialxk Jan 05 '16 at 14:03