mirror of
https://github.com/zhigang1992/react-native.git
synced 2026-04-29 04:35:36 +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;
|
@class RCTEventDispatcher;
|
||||||
|
|
||||||
@interface RCTTextField : UITextField<UITextFieldDelegate>
|
@interface RCTTextField : UITextField
|
||||||
|
|
||||||
@property (nonatomic, assign) BOOL caretHidden;
|
@property (nonatomic, assign) BOOL caretHidden;
|
||||||
@property (nonatomic, assign) BOOL autoCorrect;
|
@property (nonatomic, assign) BOOL autoCorrect;
|
||||||
@@ -22,5 +22,6 @@
|
|||||||
@property (nonatomic, strong) NSNumber *maxLength;
|
@property (nonatomic, strong) NSNumber *maxLength;
|
||||||
|
|
||||||
- (instancetype)initWithEventDispatcher:(RCTEventDispatcher *)eventDispatcher NS_DESIGNATED_INITIALIZER;
|
- (instancetype)initWithEventDispatcher:(RCTEventDispatcher *)eventDispatcher NS_DESIGNATED_INITIALIZER;
|
||||||
|
- (void)textFieldDidChange;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
@@ -27,12 +27,11 @@
|
|||||||
if ((self = [super initWithFrame:CGRectZero])) {
|
if ((self = [super initWithFrame:CGRectZero])) {
|
||||||
RCTAssert(eventDispatcher, @"eventDispatcher is a required parameter");
|
RCTAssert(eventDispatcher, @"eventDispatcher is a required parameter");
|
||||||
_eventDispatcher = eventDispatcher;
|
_eventDispatcher = eventDispatcher;
|
||||||
[self addTarget:self action:@selector(_textFieldDidChange) forControlEvents:UIControlEventEditingChanged];
|
[self addTarget:self action:@selector(textFieldDidChange) forControlEvents:UIControlEventEditingChanged];
|
||||||
[self addTarget:self action:@selector(_textFieldBeginEditing) forControlEvents:UIControlEventEditingDidBegin];
|
[self addTarget:self action:@selector(textFieldBeginEditing) forControlEvents:UIControlEventEditingDidBegin];
|
||||||
[self addTarget:self action:@selector(_textFieldEndEditing) forControlEvents:UIControlEventEditingDidEnd];
|
[self addTarget:self action:@selector(textFieldEndEditing) forControlEvents:UIControlEventEditingDidEnd];
|
||||||
[self addTarget:self action:@selector(_textFieldSubmitEditing) forControlEvents:UIControlEventEditingDidEndOnExit];
|
[self addTarget:self action:@selector(textFieldSubmitEditing) forControlEvents:UIControlEventEditingDidEndOnExit];
|
||||||
_reactSubviews = [[NSMutableArray alloc] init];
|
_reactSubviews = [[NSMutableArray alloc] init];
|
||||||
self.delegate = self;
|
|
||||||
}
|
}
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
@@ -40,31 +39,6 @@
|
|||||||
RCT_NOT_IMPLEMENTED(-initWithFrame:(CGRect)frame)
|
RCT_NOT_IMPLEMENTED(-initWithFrame:(CGRect)frame)
|
||||||
RCT_NOT_IMPLEMENTED(-initWithCoder:(NSCoder *)aDecoder)
|
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
|
- (void)setText:(NSString *)text
|
||||||
{
|
{
|
||||||
NSInteger eventLag = _nativeEventCount - _mostRecentEventCount;
|
NSInteger eventLag = _nativeEventCount - _mostRecentEventCount;
|
||||||
@@ -154,7 +128,7 @@ static void RCTUpdatePlaceholder(RCTTextField *self)
|
|||||||
return self.autocorrectionType == UITextAutocorrectionTypeYes;
|
return self.autocorrectionType == UITextAutocorrectionTypeYes;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)_textFieldDidChange
|
- (void)textFieldDidChange
|
||||||
{
|
{
|
||||||
_nativeEventCount++;
|
_nativeEventCount++;
|
||||||
[_eventDispatcher sendTextEventWithType:RCTTextEventTypeChange
|
[_eventDispatcher sendTextEventWithType:RCTTextEventTypeChange
|
||||||
@@ -163,14 +137,14 @@ static void RCTUpdatePlaceholder(RCTTextField *self)
|
|||||||
eventCount:_nativeEventCount];
|
eventCount:_nativeEventCount];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)_textFieldEndEditing
|
- (void)textFieldEndEditing
|
||||||
{
|
{
|
||||||
[_eventDispatcher sendTextEventWithType:RCTTextEventTypeEnd
|
[_eventDispatcher sendTextEventWithType:RCTTextEventTypeEnd
|
||||||
reactTag:self.reactTag
|
reactTag:self.reactTag
|
||||||
text:self.text
|
text:self.text
|
||||||
eventCount:_nativeEventCount];
|
eventCount:_nativeEventCount];
|
||||||
}
|
}
|
||||||
- (void)_textFieldSubmitEditing
|
- (void)textFieldSubmitEditing
|
||||||
{
|
{
|
||||||
[_eventDispatcher sendTextEventWithType:RCTTextEventTypeSubmit
|
[_eventDispatcher sendTextEventWithType:RCTTextEventTypeSubmit
|
||||||
reactTag:self.reactTag
|
reactTag:self.reactTag
|
||||||
@@ -178,7 +152,7 @@ static void RCTUpdatePlaceholder(RCTTextField *self)
|
|||||||
eventCount:_nativeEventCount];
|
eventCount:_nativeEventCount];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)_textFieldBeginEditing
|
- (void)textFieldBeginEditing
|
||||||
{
|
{
|
||||||
if (_selectTextOnFocus) {
|
if (_selectTextOnFocus) {
|
||||||
dispatch_async(dispatch_get_main_queue(), ^{
|
dispatch_async(dispatch_get_main_queue(), ^{
|
||||||
|
|||||||
@@ -14,13 +14,44 @@
|
|||||||
#import "RCTSparseArray.h"
|
#import "RCTSparseArray.h"
|
||||||
#import "RCTTextField.h"
|
#import "RCTTextField.h"
|
||||||
|
|
||||||
|
@interface RCTTextFieldManager() <UITextFieldDelegate>
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
@implementation RCTTextFieldManager
|
@implementation RCTTextFieldManager
|
||||||
|
|
||||||
RCT_EXPORT_MODULE()
|
RCT_EXPORT_MODULE()
|
||||||
|
|
||||||
- (UIView *)view
|
- (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)
|
RCT_EXPORT_VIEW_PROPERTY(caretHidden, BOOL)
|
||||||
|
|||||||
Reference in New Issue
Block a user