Fixes TextInput crashes when any text is entered while running as iOS app on apple silicon mac (#49320)

Summary:
Fixes https://github.com/facebook/react-native/issues/48544. We can make `RCTWeakEventEmitterWrapper` to subclass `NSDictionary` that Textinput supports encode it.

System allowed classes are:
```
Allowed classes are:
 {(
    "'NSMorphology' (0x20088b6d8) [/System/Library/Frameworks/Foundation.framework]",
    "'NSString' (0x2003f4738) [/System/Library/Frameworks/Foundation.framework]",
    "'NSInflectionRule' (0x20088d348) [/System/Library/Frameworks/Foundation.framework]",
    "'UIColor' (0x2006c0520) [/System/iOSSupport/System/Library/PrivateFrameworks/UIKitCore.framework]",
    "'NSTextAttachment' (0x20042af98) [/System/Library/PrivateFrameworks/UIFoundation.framework]",
    "'NSShadow' (0x20042ae30) [/System/Library/PrivateFrameworks/UIFoundation.framework]",
    "'NSTextEncapsulation' (0x200897e50) [/System/Library/Frameworks/CoreText.framework]",
    "'NSTextAlternatives' (0x20042af70) [/System/Library/PrivateFrameworks/UIFoundation.framework]",
    "'NSFont' (0x20042a9f8) [/System/Library/PrivateFrameworks/UIFoundation.framework]",
    "'NSAttributedString' (0x2003f3838) [/System/Library/Frameworks/Foundation.framework]",
    "'NSData' (0x2003ed528) [/System/Library/Frameworks/CoreFoundation.framework]",
    "'NSURL' (0x2003ed938) [/System/Library/Frameworks/CoreFoundation.framework]",
    "'NSAdaptiveImageGlyph' (0x2008ae538) [/System/Library/PrivateFrameworks/UIFoundation.framework]",
    "'NSNumber' (0x2003f4238) [/System/Library/Frameworks/Foundation.framework]",
    "'NSParagraphStyle' (0x20042ad40) [/System/Library/PrivateFrameworks/UIFoundation.framework]",
    "'NSDictionary' (0x2003ed5a0) [/System/Library/Frameworks/CoreFoundation.framework]",
    "'UIFont' (0x20042c668) [/System/Library/PrivateFrameworks/UIFoundation.framework]",
    "'NSColor' (0x200412350) [/System/Library/Frameworks/AppKit.framework]",
    "'NSGlyphInfo' (0x20042aa98) [/System/Library/PrivateFrameworks/UIFoundation.framework]",
    "'NSArray' (0x2003ed460) [/System/Library/Frameworks/CoreFoundation.framework]",
    "'NSPresentationIntent' (0x20088da28) [/System/Library/Frameworks/Foundation.framework]"
)}
```

## Changelog:

[IOS] [FIXED] -  Fixes TextInput crashes when any text is entered while running as iOS app on apple silicon mac

Pull Request resolved: https://github.com/facebook/react-native/pull/49320

Test Plan:
Run RNTester on apple silicon mac, and entered some text in textinput, no crash occured. Also, verified that the caret was not jumping around, thus preserving the original fix.

https://github.com/user-attachments/assets/6304f6e7-c663-4351-ace8-ab1842ee545f

Reviewed By: javache

Differential Revision: D69981500

Pulled By: cipolleschi

fbshipit-source-id: 2af9b280e42f621446efda9b101af50525e8fef7
This commit is contained in:
zhongwuzw
2025-03-11 14:24:17 +00:00
committed by React Native Bot
parent 68055f2d8a
commit e2b081e66f
4 changed files with 30 additions and 58 deletions
@@ -99,11 +99,7 @@ static NSSet<NSNumber *> *returnKeyTypesSet;
NSMutableDictionary<NSAttributedStringKey, id> *defaultAttributes =
[_backedTextInputView.defaultTextAttributes mutableCopy];
#if !TARGET_OS_MACCATALYST
RCTWeakEventEmitterWrapper *eventEmitterWrapper = [RCTWeakEventEmitterWrapper new];
eventEmitterWrapper.eventEmitter = _eventEmitter;
defaultAttributes[RCTAttributedStringEventEmitterKey] = eventEmitterWrapper;
#endif
defaultAttributes[RCTAttributedStringEventEmitterKey] = RCTWrapEventEmitter(_eventEmitter);
_backedTextInputView.defaultTextAttributes = defaultAttributes;
}
@@ -263,10 +259,8 @@ static NSSet<NSNumber *> *returnKeyTypesSet;
if (newTextInputProps.textAttributes != oldTextInputProps.textAttributes) {
NSMutableDictionary<NSAttributedStringKey, id> *defaultAttributes =
RCTNSTextAttributesFromTextAttributes(newTextInputProps.getEffectiveTextAttributes(RCTFontSizeMultiplier()));
#if !TARGET_OS_MACCATALYST
defaultAttributes[RCTAttributedStringEventEmitterKey] =
_backedTextInputView.defaultTextAttributes[RCTAttributedStringEventEmitterKey];
#endif
_backedTextInputView.defaultTextAttributes = defaultAttributes;
}
@@ -52,8 +52,29 @@ BOOL RCTIsAttributedStringEffectivelySame(
NSDictionary<NSAttributedStringKey, id> *insensitiveAttributes,
const facebook::react::TextAttributes &baseTextAttributes);
@interface RCTWeakEventEmitterWrapper : NSObject
@property (nonatomic, assign) facebook::react::SharedEventEmitter eventEmitter;
@end
static inline NSData *RCTWrapEventEmitter(const facebook::react::SharedEventEmitter &eventEmitter)
{
auto eventEmitterPtr = new std::weak_ptr<const facebook::react::EventEmitter>(eventEmitter);
return [[NSData alloc] initWithBytesNoCopy:eventEmitterPtr
length:sizeof(eventEmitterPtr)
deallocator:^(void *ptrToDelete, NSUInteger) {
delete (std::weak_ptr<facebook::react::EventEmitter> *)ptrToDelete;
}];
}
static inline facebook::react::SharedEventEmitter RCTUnwrapEventEmitter(NSData *data)
{
if (data.length == 0) {
return nullptr;
}
auto weakPtr = dynamic_cast<std::weak_ptr<const facebook::react::EventEmitter> *>(
(std::weak_ptr<const facebook::react::EventEmitter> *)data.bytes);
if (weakPtr) {
return weakPtr->lock();
}
return nullptr;
}
NS_ASSUME_NONNULL_END
@@ -16,45 +16,6 @@
using namespace facebook::react;
@implementation RCTWeakEventEmitterWrapper {
std::weak_ptr<const EventEmitter> _weakEventEmitter;
}
- (void)setEventEmitter:(SharedEventEmitter)eventEmitter
{
_weakEventEmitter = eventEmitter;
}
- (SharedEventEmitter)eventEmitter
{
return _weakEventEmitter.lock();
}
- (void)dealloc
{
_weakEventEmitter.reset();
}
- (BOOL)isEqual:(id)object
{
// We consider the underlying EventEmitter as the identity
if (![object isKindOfClass:[self class]]) {
return NO;
}
auto thisEventEmitter = [self eventEmitter];
auto otherEventEmitter = [((RCTWeakEventEmitterWrapper *)object) eventEmitter];
return thisEventEmitter == otherEventEmitter;
}
- (NSUInteger)hash
{
// We consider the underlying EventEmitter as the identity
return (NSUInteger)_weakEventEmitter.lock().get();
}
@end
inline static UIFontWeight RCTUIFontWeightFromInteger(NSInteger fontWeight)
{
assert(fontWeight > 50);
@@ -405,10 +366,8 @@ static NSMutableAttributedString *RCTNSAttributedStringFragmentWithAttributesFro
{
auto nsAttributedStringFragment = RCTNSAttributedStringFragmentFromFragment(fragment, placeholderImage);
#if !TARGET_OS_MACCATALYST
if (fragment.parentShadowView.componentHandle) {
RCTWeakEventEmitterWrapper *eventEmitterWrapper = [RCTWeakEventEmitterWrapper new];
eventEmitterWrapper.eventEmitter = fragment.parentShadowView.eventEmitter;
auto eventEmitterWrapper = RCTWrapEventEmitter(fragment.parentShadowView.eventEmitter);
NSDictionary<NSAttributedStringKey, id> *additionalTextAttributes =
@{RCTAttributedStringEventEmitterKey : eventEmitterWrapper};
@@ -416,7 +375,6 @@ static NSMutableAttributedString *RCTNSAttributedStringFragmentWithAttributesFro
[nsAttributedStringFragment addAttributes:additionalTextAttributes
range:NSMakeRange(0, nsAttributedStringFragment.length)];
}
#endif
return nsAttributedStringFragment;
}
@@ -280,11 +280,10 @@ static NSLineBreakMode RCTNSLineBreakModeFromEllipsizeMode(EllipsizeMode ellipsi
// after (fraction == 1.0) the last character, then the attribute is valid.
if (textStorage.length > 0 && (fraction > 0 || characterIndex > 0) &&
(fraction < 1 || characterIndex < textStorage.length - 1)) {
RCTWeakEventEmitterWrapper *eventEmitterWrapper =
(RCTWeakEventEmitterWrapper *)[textStorage attribute:RCTAttributedStringEventEmitterKey
atIndex:characterIndex
effectiveRange:NULL];
return eventEmitterWrapper.eventEmitter;
NSData *eventEmitterWrapper = (NSData *)[textStorage attribute:RCTAttributedStringEventEmitterKey
atIndex:characterIndex
effectiveRange:NULL];
return RCTUnwrapEventEmitter(eventEmitterWrapper);
}
return nil;