mirror of
https://github.com/zhigang1992/react-native.git
synced 2026-02-12 09:20:14 +08:00
[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:
@@ -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
|
||||
|
||||
@@ -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(), ^{
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user