I am trying to set the text of UITextView
which has some illegal characters like "Unicode Character 'OBJECT REPLACEMENT CHARACTER' (U+FFFC)".
Basically, I have a UITextView
. Now user taps on it and keyboard comes up. Now I use speech to text from keyboard(also known as dictation). When the dictation is processing(at that time UITextView
has that special character which corresponds to the default placeholder animation), I try to set the value of text view using:
textView.text = @""
This creates following crash:
*** Terminating app due to uncaught exception 'NSRangeException', reason: '-[__NSCFString replaceCharactersInRange:withString:]: Range or index out of bounds'
Stack trace which I got from crashlytics:
0 CoreFoundation __exceptionPreprocess + 130
2 CoreFoundation -[NSException initWithCoder:]
3 CoreFoundation mutateError + 222
4 Foundation -[NSString stringByReplacingCharactersInRange:withString:] + 134
5 UIKit __37-[UITextInputController textInRange:]_block_invoke + 310
6 UIFoundation -[NSTextStorage coordinateReading:] + 36
7 UIKit -[UITextInputController textInRange:] + 232
8 UIKit -[TIDocumentState(UITextInputAdditions) _contextAfterPosition:inDocument:] + 190
9 UIKit -[TIDocumentState(UITextInputAdditions) initWithDocument:] + 150
10 UIKit +[TIDocumentState(UITextInputAdditions) documentStateOfDocument:] + 52
11 UIKit -[UIKeyboardImpl updateForChangedSelectionWithExecutionContext:] + 288
12 UIKit -[UIKeyboardTaskQueue continueExecutionOnMainThread] + 352
13 UIKit -[UIKeyboardTaskQueue performTask:] + 248
14 UIKit -[UIKeyboardImpl updateForChangedSelection] + 96
15 UIKit -[UIKeyboardImpl selectionDidChange:] + 102
16 UIFoundation -[NSTextStorage coordinateReading:] + 36
17 UIKit -[UITextInputController _coordinateSelectionChange:] + 100
18 UIKit -[UITextInputController _setSelectedTextRange:] + 604
19 UIKit -[UITextView setAttributedText:] + 392
20 UIKit -[UITextView setText:] + 134
I have also created a sample project which demonstrates this problem. You can get this project from: https://dl.dropboxusercontent.com/u/80141854/TextViewDictationCheck.zip
Exception can be reproduced by following steps:
I have found one method of avoiding this crash:
While setting the text of UITextView, we can use following code:
I have also found one more workaround which we can use while resetting text on UITextView:
[self.textView setSelectedRange:NSMakeRange(0, [[self.textView textStorage] length])];
[self.textView insertText:@""];
[self.textView setText:@""];
But I am still not getting that why this crash happens if we only use setText: to set the text.
The exception happens in the Foundation code, not your code. There is a race condition that causes this crash if the string is altered while the dictation is being processed. It places a placeholder into the string when you touch the microphone button, then replaces it with the text when it's finished processing. If you alter the string and remove the placeholder, it causes a crash.
The fix is to make sure you don't alter the string while dictation is being processed. You can do this by checking the current input mode primary language. It's set to dictation
while dictation is in progress:
- (IBAction)sendPressed:(id)sender
{
NSString *primaryLanguage = [self.textView textInputMode].primaryLanguage;
if(![primaryLanguage isEqualToString:@"dictation"])
{
// Your original method body:
NSString *textViewText = self.textView.text;
textViewText = @"";
self.textView.text = nil;
self.textView.text = @"";
}
}
This skips the code to empty the textview if dictation is in progress.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With