Implement the nativeID functionality in a more efficient way (#23662)

Summary:
Implement TODO, implement the nativeID functionality in a more efficient way instead of searching the whole view tree.

[iOS] [Fixed] - Implement the nativeID functionality in a more efficient way
Pull Request resolved: https://github.com/facebook/react-native/pull/23662

Differential Revision: D14323747

Pulled By: shergin

fbshipit-source-id: 3d45dbf53ad2b6adb79b4331600d53b51ede76d4
This commit is contained in:
zhongwuzw
2019-03-05 09:37:47 -08:00
committed by Facebook Github Bot
parent 50d095ce32
commit b7b8836a7f
3 changed files with 46 additions and 18 deletions

View File

@@ -135,6 +135,14 @@ RCT_EXTERN NSString *const RCTUIManagerWillUpdateViewsDueToContentSizeMultiplier
*/
- (UIView *)viewForNativeID:(NSString *)nativeID withRootTag:(NSNumber *)rootTag;
/**
* Register a view that is tagged with nativeID as its nativeID prop
*
* @param nativeID the id reference to native component relative to root view.
* @param view the view that is tagged with nativeID as its nativeID prop.
*/
- (void)setNativeID:(NSString *)nativeID forView:(UIView *)view;
/**
* The view that is currently first responder, according to the JS context.
*/

View File

@@ -50,6 +50,14 @@ static void RCTTraverseViewNodes(id<RCTComponent> view, void (^block)(id<RCTComp
}
}
static NSString *RCTNativeIDRegistryKey(NSString *nativeID, NSNumber *rootTag)
{
if (!nativeID || !rootTag) {
return @"";
}
return [NSString stringWithFormat:@"%@-%@", rootTag, nativeID];
}
NSString *const RCTUIManagerWillUpdateViewsDueToContentSizeMultiplierChangeNotification = @"RCTUIManagerWillUpdateViewsDueToContentSizeMultiplierChangeNotification";
@implementation RCTUIManager
@@ -63,6 +71,7 @@ NSString *const RCTUIManagerWillUpdateViewsDueToContentSizeMultiplierChangeNotif
NSMutableDictionary<NSNumber *, RCTShadowView *> *_shadowViewRegistry; // RCT thread only
NSMutableDictionary<NSNumber *, UIView *> *_viewRegistry; // Main thread only
NSMapTable<NSString *, UIView *> *_nativeIDRegistry; // Main thread only
NSMapTable<RCTShadowView *, NSArray<NSString *> *> *_shadowViewsWithUpdatedProps; // UIManager queue only.
NSHashTable<RCTShadowView *> *_shadowViewsWithUpdatedChildren; // UIManager queue only.
@@ -106,6 +115,7 @@ RCT_EXPORT_MODULE()
self->_rootViewTags = nil;
self->_shadowViewRegistry = nil;
self->_viewRegistry = nil;
self->_nativeIDRegistry = nil;
self->_bridge = nil;
[[NSNotificationCenter defaultCenter] removeObserver:self];
@@ -131,6 +141,15 @@ RCT_EXPORT_MODULE()
return _viewRegistry;
}
- (NSMapTable *)nativeIDRegistry
{
// Should be called on main queue
if (!_nativeIDRegistry) {
_nativeIDRegistry = [NSMapTable strongToWeakObjectsMapTable];
}
return _nativeIDRegistry;
}
- (void)setBridge:(RCTBridge *)bridge
{
RCTAssert(_bridge == nil, @"Should not re-use same UIManager instance");
@@ -138,6 +157,7 @@ RCT_EXPORT_MODULE()
_shadowViewRegistry = [NSMutableDictionary new];
_viewRegistry = [NSMutableDictionary new];
_nativeIDRegistry = [NSMapTable strongToWeakObjectsMapTable];
_shadowViewsWithUpdatedProps = [NSMapTable weakToStrongObjectsMapTable];
_shadowViewsWithUpdatedChildren = [NSHashTable weakObjectsHashTable];
@@ -366,31 +386,27 @@ static NSDictionary *deviceOrientationEventBody(UIDeviceOrientation orientation)
} forTag:view.reactTag];
}
/**
* TODO(yuwang): implement the nativeID functionality in a more efficient way
* instead of searching the whole view tree
*/
- (UIView *)viewForNativeID:(NSString *)nativeID withRootTag:(NSNumber *)rootTag
{
RCTAssertMainQueue();
UIView *view = [self viewForReactTag:rootTag];
return [self _lookupViewForNativeID:nativeID inView:view];
if (!nativeID || !rootTag) {
return nil;
}
return [_nativeIDRegistry objectForKey:RCTNativeIDRegistryKey(nativeID, rootTag)];
}
- (UIView *)_lookupViewForNativeID:(NSString *)nativeID inView:(UIView *)view
- (void)setNativeID:(NSString *)nativeID forView:(UIView *)view
{
RCTAssertMainQueue();
if (view != nil && [nativeID isEqualToString:view.nativeID]) {
return view;
if (!nativeID) {
return;
}
for (UIView *subview in view.subviews) {
UIView *targetView = [self _lookupViewForNativeID:nativeID inView:subview];
if (targetView != nil) {
return targetView;
__weak RCTUIManager *weakSelf = self;
[self rootViewForReactTag:view.reactTag withCompletion:^(UIView *rootView) {
if (rootView) {
[weakSelf.nativeIDRegistry setObject:view forKey:RCTNativeIDRegistryKey(nativeID, rootView.reactTag)];
}
}
return nil;
}];
}
- (void)setSize:(CGSize)size forView:(UIView *)view

View File

@@ -105,8 +105,6 @@ RCT_EXPORT_VIEW_PROPERTY(hasTVPreferredFocus, BOOL)
RCT_EXPORT_VIEW_PROPERTY(tvParallaxProperties, NSDictionary)
#endif
RCT_EXPORT_VIEW_PROPERTY(nativeID, NSString)
// Acessibility related properties
RCT_REMAP_VIEW_PROPERTY(accessible, reactAccessibilityElement.isAccessibilityElement, BOOL)
RCT_REMAP_VIEW_PROPERTY(accessibilityActions, reactAccessibilityElement.accessibilityActions, NSArray<NSString *>)
@@ -171,6 +169,12 @@ RCT_CUSTOM_VIEW_PROPERTY(accessibilityStates, UIAccessibilityTraits, RCTView)
view.reactAccessibilityElement.accessibilityTraits = (view.reactAccessibilityElement.accessibilityTraits & ~AccessibilityStatesMask) | maskedTraits;
}
RCT_CUSTOM_VIEW_PROPERTY(nativeID, NSString *, RCTView)
{
view.nativeID = json ? [RCTConvert NSString:json] : defaultView.nativeID;
[_bridge.uiManager setNativeID:view.nativeID forView:view];
}
RCT_CUSTOM_VIEW_PROPERTY(pointerEvents, RCTPointerEvents, RCTView)
{
if ([view respondsToSelector:@selector(setPointerEvents:)]) {