cb428 cb428 - 4 months ago 7
iOS Question

"Cannot Increment endIndex" because of emoji

I have a function that finds the current word a user has selected in a UITextView. However, if I call this function when an emoji is in the UITextView.text property, I see a crash. I believe this is because of the different character counts in String vs NSString.

How do I properly convert this?

func currentWord() -> String {

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

// crash occurs here
let beginRange = Range(text.startIndex.advancedBy(0) ..< text.startIndex.advancedBy(cursorPosition))
let endRange = Range(text.startIndex.advancedBy(cursorPosition) ..< text.startIndex.advancedBy(text.characters.count))

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

let beginWords = beginPhrase.componentsSeparatedByCharactersInSet(separationCharacters)
let endWords = endPhrase.componentsSeparatedByCharactersInSet(separationCharacters)

return beginWords.last! + endWords.first!
}

Answer

I believe this is because of the different character counts in String vs NSString

You're right about that. You are shifting back and forth between using NSRange (Cocoa) and Range (Swift) — and they work differently. And NSString (Cocoa) and String (Swift) have different ideas of where the character boundaries are. You need to be consistent.

Once you've used selectedRange in the first line, you are in the Cocoa world of NSRange. You need to stay consistently in the Cocoa world. Don't use any Swift Ranges! Don't use any Swift characters!

Form your beginRange entirely using NSRange — for example, call NSMakeRange. Don't use characters.count; stay in the NSString world and use the string's length (in Swift, that is its utf16.count). Then all will be well.