Post

Replies

Boosts

Views

Activity

Reply to UITextView Runtime Error Occurrence (attempt to create NSTextRange from nil location)
Thank you for the reproduction sample! I do have the same crash reports for my app, but was unable to reproduce and thus debug it. With your sample I've set with the following workaround: import UIKit extension NSTextStorage { // Newline characters must not be followed by variation selector. // This invalid sequence sometimes appears in UITextView when adding newline // in certain combinations of characters. // For instance, if you insert this string: // [[string from https://shorturl.at/uISV7, blocked by Apple for some reason]] // then place cursor before first ❤️ and press return, // you get a string in which there's a substring "\nu{FE0F}" // for which UITextView by a series of calls tries to get NSTextLocation // which leads to objc exception being thrown. // This method fixed this by moving newline to where it belongs: // back to the first location that isn't variation selector // (presumably it's the symbol to which variation selector actually belongs). @objc fileprivate func fixInvalidVariationSelectorsAndProcessEditing() { struct InvalidNewline { var location: Int var desiredLocation: Int } var invalidLocations: [InvalidNewline] = [] let utf16 = Array(string.utf16) let newline: UInt16 = 0x000A for index in utf16.indices.dropLast() { if utf16[index] == newline, utf16[index + 1].isVariationSelector { var properIndex = index - 1 while properIndex > 0, utf16[properIndex].isVariationSelector == true { properIndex -= 1 } invalidLocations.append(.init(location: index, desiredLocation: properIndex)) } } invalidLocations.forEach { mutableString.deleteCharacters(in: NSRange(location: $0.location, length: 1)) mutableString.insert("\n", at: $0.desiredLocation) } // Call original method which is swizzed by this fixInvalidVariationSelectorsAndProcessEditing() } static func fixInvalidVariationSelectors() { method_exchangeImplementations( class_getInstanceMethod(Self.self, #selector(fixInvalidVariationSelectorsAndProcessEditing))!, class_getInstanceMethod(Self.self, #selector(processEditing))! ) } } extension UInt16 { fileprivate var isVariationSelector: Bool { Unicode.Scalar(self)?.properties.isVariationSelector == true } } I've tried my best to describe the origin of the crash and how it's fixed in the comments above the method. There's still a minor issue though: after adding a newline in the buggy spot, trying to delete it using backspace leads to ❤️ being removed instead of newline (while the cursor is visually located at the left side of ❤️). I assume that there should be similar way to work around this bug too, but I didn't bother.
Aug ’24