Created
October 8, 2015 16:47
-
-
Save danielgomezrico/75a9a02cb27f02c4b35f to your computer and use it in GitHub Desktop.
iOS - Swift - UITextView scroll to bottom extension
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import UIKit | |
extension UITextView { | |
func scrollToBotom() { | |
let range = NSMakeRange(text.characters.count - 1, 1); | |
scrollRangeToVisible(range); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This is both slow with a lot of text (the .count property accessor is O(n) for collections which do not conform to SequenceType, and you will see very noticeable slowdowns once you get to 100,000+ characters), and doesn't work properly with things like emoji.
Here's why: scrollRangeToVisible expects an NSRange over the content of the NSTextStorage object, which is an NSAttributedString and stores its actual text content as an NSString, which is indexed by UTF-16 code units. A Swift String's .characters member, on the other hand, presents the String's content as a collection of Unicode extended grapheme clusters (which correspond to visible characters a.k.a. glyphs).
In cases where there is not a one-to-one mapping between UTF-16 code units and extended grapheme clusters (such as with emoji, which generally require two UTF-16 code units to represent — see https://www.objc.io/issues/9-strings/unicode/ for a good discussion), .characters.count of String will report a very different value than .length of NSString.
Fortunately, there is a simple modification which solves both problems (speed and full Unicode compatibility). Just replace this line:
let range = NSMakeRange(text.characters.count - 1, 1);
with this line:
let range = NSMakeRange((text as NSString).length - 1, 1);
That's it.