[ReactNative] Fix RCTTextField crash on iOS7

Summary:
RCTTextField was its own delegate, that was causing a stall on the main thread,
see more here:
http://stackoverflow.com/questions/19758025/uitextfield-delegate-jumping-to-100-cpu-usage-and-crashing-upon-using-keyboard
This commit is contained in:
Tadeu Zagallo
2015-08-06 09:53:20 -07:00
parent 0d981c06de
commit 48548fedbf
3 changed files with 42 additions and 36 deletions

View File

@@ -11,7 +11,7 @@
@class RCTEventDispatcher;
@interface RCTTextField : UITextField<UITextFieldDelegate>
@interface RCTTextField : UITextField
@property (nonatomic, assign) BOOL caretHidden;
@property (nonatomic, assign) BOOL autoCorrect;
@@ -22,5 +22,6 @@
@property (nonatomic, strong) NSNumber *maxLength;
- (instancetype)initWithEventDispatcher:(RCTEventDispatcher *)eventDispatcher NS_DESIGNATED_INITIALIZER;
- (void)textFieldDidChange;
@end

View File

@@ -27,12 +27,11 @@
if ((self = [super initWithFrame:CGRectZero])) {
RCTAssert(eventDispatcher, @"eventDispatcher is a required parameter");
_eventDispatcher = eventDispatcher;
[self addTarget:self action:@selector(_textFieldDidChange) forControlEvents:UIControlEventEditingChanged];
[self addTarget:self action:@selector(_textFieldBeginEditing) forControlEvents:UIControlEventEditingDidBegin];
[self addTarget:self action:@selector(_textFieldEndEditing) forControlEvents:UIControlEventEditingDidEnd];
[self addTarget:self action:@selector(_textFieldSubmitEditing) forControlEvents:UIControlEventEditingDidEndOnExit];
[self addTarget:self action:@selector(textFieldDidChange) forControlEvents:UIControlEventEditingChanged];
[self addTarget:self action:@selector(textFieldBeginEditing) forControlEvents:UIControlEventEditingDidBegin];
[self addTarget:self action:@selector(textFieldEndEditing) forControlEvents:UIControlEventEditingDidEnd];
[self addTarget:self action:@selector(textFieldSubmitEditing) forControlEvents:UIControlEventEditingDidEndOnExit];
_reactSubviews = [[NSMutableArray alloc] init];
self.delegate = self;
}
return self;
}
@@ -40,31 +39,6 @@
RCT_NOT_IMPLEMENTED(-initWithFrame:(CGRect)frame)
RCT_NOT_IMPLEMENTED(-initWithCoder:(NSCoder *)aDecoder)
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
if (_maxLength == nil || [string isEqualToString:@"\n"]) { // Make sure forms can be submitted via return
return YES;
}
NSUInteger allowedLength = _maxLength.integerValue - textField.text.length + range.length;
if (string.length > allowedLength) {
if (string.length > 1) {
// Truncate the input string so the result is exactly maxLength
NSString *limitedString = [string substringToIndex:allowedLength];
NSMutableString *newString = textField.text.mutableCopy;
[newString replaceCharactersInRange:range withString:limitedString];
textField.text = newString;
// Collapse selection at end of insert to match normal paste behavior
UITextPosition *insertEnd = [textField positionFromPosition:textField.beginningOfDocument
offset:(range.location + allowedLength)];
textField.selectedTextRange = [textField textRangeFromPosition:insertEnd toPosition:insertEnd];
[self _textFieldDidChange];
}
return NO;
} else {
return YES;
}
}
- (void)setText:(NSString *)text
{
NSInteger eventLag = _nativeEventCount - _mostRecentEventCount;
@@ -154,7 +128,7 @@ static void RCTUpdatePlaceholder(RCTTextField *self)
return self.autocorrectionType == UITextAutocorrectionTypeYes;
}
- (void)_textFieldDidChange
- (void)textFieldDidChange
{
_nativeEventCount++;
[_eventDispatcher sendTextEventWithType:RCTTextEventTypeChange
@@ -163,14 +137,14 @@ static void RCTUpdatePlaceholder(RCTTextField *self)
eventCount:_nativeEventCount];
}
- (void)_textFieldEndEditing
- (void)textFieldEndEditing
{
[_eventDispatcher sendTextEventWithType:RCTTextEventTypeEnd
reactTag:self.reactTag
text:self.text
eventCount:_nativeEventCount];
}
- (void)_textFieldSubmitEditing
- (void)textFieldSubmitEditing
{
[_eventDispatcher sendTextEventWithType:RCTTextEventTypeSubmit
reactTag:self.reactTag
@@ -178,7 +152,7 @@ static void RCTUpdatePlaceholder(RCTTextField *self)
eventCount:_nativeEventCount];
}
- (void)_textFieldBeginEditing
- (void)textFieldBeginEditing
{
if (_selectTextOnFocus) {
dispatch_async(dispatch_get_main_queue(), ^{

View File

@@ -14,13 +14,44 @@
#import "RCTSparseArray.h"
#import "RCTTextField.h"
@interface RCTTextFieldManager() <UITextFieldDelegate>
@end
@implementation RCTTextFieldManager
RCT_EXPORT_MODULE()
- (UIView *)view
{
return [[RCTTextField alloc] initWithEventDispatcher:self.bridge.eventDispatcher];
RCTTextField *textField = [[RCTTextField alloc] initWithEventDispatcher:self.bridge.eventDispatcher];
textField.delegate = self;
return textField;
}
- (BOOL)textField:(RCTTextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
if (textField.maxLength == nil || [string isEqualToString:@"\n"]) { // Make sure forms can be submitted via return
return YES;
}
NSUInteger allowedLength = textField.maxLength.integerValue - textField.text.length + range.length;
if (string.length > allowedLength) {
if (string.length > 1) {
// Truncate the input string so the result is exactly maxLength
NSString *limitedString = [string substringToIndex:allowedLength];
NSMutableString *newString = textField.text.mutableCopy;
[newString replaceCharactersInRange:range withString:limitedString];
textField.text = newString;
// Collapse selection at end of insert to match normal paste behavior
UITextPosition *insertEnd = [textField positionFromPosition:textField.beginningOfDocument
offset:(range.location + allowedLength)];
textField.selectedTextRange = [textField textRangeFromPosition:insertEnd toPosition:insertEnd];
[textField textFieldDidChange];
}
return NO;
} else {
return YES;
}
}
RCT_EXPORT_VIEW_PROPERTY(caretHidden, BOOL)