Skip to content

Commit

Permalink
iOS: attach rootTag to the native component instance for easy access
Browse files Browse the repository at this point in the history
Summary:
Changelog: [Internal]

The main use-case here is to get the rootTag off RCTImageView, for image loading instrumentation. The fact is, each RCTView subclass already has `reactTag` attached today. We already have the `rootTag` when the view is created by the UIManager, so why not just attach it like reactTag? If we don't, looking up the rootTag from the native component is non-trivial and extremely inefficient (have to jump to shadow queue, back to main queue, etc).

Reviewed By: sammy-SC

Differential Revision: D18497002

fbshipit-source-id: 8409e3a1c95e09accedd959592cbf178fab0b2c3
  • Loading branch information
fkgozali authored and facebook-github-bot committed Nov 16, 2019
1 parent 13a9a03 commit 446705d
Show file tree
Hide file tree
Showing 9 changed files with 41 additions and 24 deletions.
33 changes: 18 additions & 15 deletions Libraries/Image/RCTImageView.mm
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,14 @@
#import <React/RCTBridge.h>
#import <React/RCTConvert.h>
#import <React/RCTEventDispatcher.h>
#import <React/RCTImageBlurUtils.h>
#import <React/RCTImageSource.h>
#import <React/RCTImageUtils.h>
#import <React/RCTImageLoaderWithAttributionProtocol.h>
#import <React/RCTUIImageViewAnimated.h>
#import <React/RCTUtils.h>
#import <React/UIView+React.h>

#import <React/RCTUIImageViewAnimated.h>
#import <React/RCTImageBlurUtils.h>
#import <React/RCTImageUtils.h>
#import <React/RCTImageLoaderProtocol.h>

/**
* Determines whether an image of `currentSize` should be reloaded for display
* at `idealSize`.
Expand Down Expand Up @@ -80,7 +79,7 @@ @implementation RCTImageView
// Whether the latest change of props requires the image to be reloaded
BOOL _needsReload;

RCTUIImageViewAnimated *_imageView;
RCTUIImageViewAnimated *_imageView;
}

- (instancetype)initWithBridge:(RCTBridge *)bridge
Expand Down Expand Up @@ -320,15 +319,19 @@ - (void)reloadImage
[weakSelf imageLoaderLoadedImage:loadedImage error:error forImageSource:source partial:NO];
};

_reloadImageCancellationBlock =
[[_bridge moduleForName:@"ImageLoader" lazilyLoadIfNecessary:YES] loadImageWithURLRequest:source.request
size:imageSize
scale:imageScale
clipped:NO
resizeMode:_resizeMode
progressBlock:progressHandler
partialLoadBlock:partialLoadHandler
completionBlock:completionHandler];
id<RCTImageLoaderWithAttributionProtocol> imageLoader = [_bridge moduleForName:@"ImageLoader"
lazilyLoadIfNecessary:YES];
_reloadImageCancellationBlock = [imageLoader loadImageWithURLRequest:source.request
size:imageSize
scale:imageScale
clipped:NO
resizeMode:_resizeMode
attribution:{
.surfaceId = [self.rootTag intValue],
}
progressBlock:progressHandler
partialLoadBlock:partialLoadHandler
completionBlock:completionHandler];
} else {
[self clearImage];
}
Expand Down
2 changes: 1 addition & 1 deletion React/Modules/RCTUIManager.m
Original file line number Diff line number Diff line change
Expand Up @@ -988,7 +988,7 @@ - (void)_manageChildren:(NSNumber *)containerTag
return;
}

preliminaryCreatedView = [componentData createViewWithTag:reactTag];
preliminaryCreatedView = [componentData createViewWithTag:reactTag rootTag:rootTag];

if (preliminaryCreatedView) {
self->_viewRegistry[reactTag] = preliminaryCreatedView;
Expand Down
8 changes: 4 additions & 4 deletions React/Profiler/RCTProfile.m
Original file line number Diff line number Diff line change
Expand Up @@ -209,10 +209,10 @@ void RCTProfileTrampolineEnd(void)
RCT_PROFILE_END_EVENT(RCTProfileTagAlways, @"objc_call,modules,auto");
}

static UIView *(*originalCreateView)(RCTComponentData *, SEL, NSNumber *);
static UIView *RCTProfileCreateView(RCTComponentData *self, SEL _cmd, NSNumber *tag)
static UIView *(*originalCreateView)(RCTComponentData *, SEL, NSNumber *, NSNumber *);
static UIView *RCTProfileCreateView(RCTComponentData *self, SEL _cmd, NSNumber *tag, NSNumber *rootTag)
{
UIView *view = originalCreateView(self, _cmd, tag);
UIView *view = originalCreateView(self, _cmd, tag, rootTag);
RCTProfileHookInstance(view);
return view;
}
Expand All @@ -224,7 +224,7 @@ static void RCTProfileHookUIManager(RCTUIManager *uiManager)
RCTProfileHookInstance([uiManager viewForReactTag:view]);
}

Method createView = class_getInstanceMethod([RCTComponentData class], @selector(createViewWithTag:));
Method createView = class_getInstanceMethod([RCTComponentData class], @selector(createViewWithTag:rootTag:));

if (method_getImplementation(createView) != (IMP)RCTProfileCreateView) {
originalCreateView = (typeof(originalCreateView))method_getImplementation(createView);
Expand Down
1 change: 1 addition & 0 deletions React/Views/RCTComponent.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ typedef void (^RCTBubblingEventBlock)(NSDictionary *body);
@protocol RCTComponent <NSObject>

@property (nonatomic, copy) NSNumber *reactTag;
@property (nonatomic, copy) NSNumber *rootTag;

- (void)insertReactSubview:(id<RCTComponent>)subview atIndex:(NSInteger)atIndex;
- (void)removeReactSubview:(id<RCTComponent>)subview;
Expand Down
2 changes: 1 addition & 1 deletion React/Views/RCTComponentData.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
- (instancetype)initWithManagerClass:(Class)managerClass
bridge:(RCTBridge *)bridge NS_DESIGNATED_INITIALIZER;

- (UIView *)createViewWithTag:(NSNumber *)tag;
- (UIView *)createViewWithTag:(NSNumber *)tag rootTag:(NSNumber *)rootTag;
- (RCTShadowView *)createShadowViewWithTag:(NSNumber *)tag;
- (void)setProps:(NSDictionary<NSString *, id> *)props forView:(id<RCTComponent>)view;
- (void)setProps:(NSDictionary<NSString *, id> *)props forShadowView:(RCTShadowView *)shadowView;
Expand Down
5 changes: 3 additions & 2 deletions React/Views/RCTComponentData.m
Original file line number Diff line number Diff line change
Expand Up @@ -66,12 +66,13 @@ - (RCTViewManager *)manager

RCT_NOT_IMPLEMENTED(- (instancetype)init)

- (UIView *)createViewWithTag:(NSNumber *)tag
- (UIView *)createViewWithTag:(NSNumber *)tag rootTag:(NSNumber *)rootTag
{
RCTAssertMainQueue();

UIView *view = [self.manager view];
view.reactTag = tag;
view.rootTag = rootTag;
#if !TARGET_OS_TV
view.multipleTouchEnabled = YES;
#endif
Expand All @@ -94,7 +95,7 @@ - (void)callCustomSetter:(SEL)setter onView:(id<RCTComponent>)view withProp:(id)
if (!isShadowView) {
if (!json && !_defaultView) {
// Only create default view if json is null
_defaultView = [self createViewWithTag:nil];
_defaultView = [self createViewWithTag:nil rootTag:nil];
}
((void (*)(id, SEL, id, id, id))objc_msgSend)(self.manager, setter, json, view, _defaultView);
} else {
Expand Down
1 change: 1 addition & 0 deletions React/Views/RCTShadowView.m
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ + (YGConfigRef)yogaConfig
}

@synthesize reactTag = _reactTag;
@synthesize rootTag = _rootTag;

// YogaNode API

Expand Down
10 changes: 10 additions & 0 deletions React/Views/UIView+React.m
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,16 @@ - (void)setReactTag:(NSNumber *)reactTag
objc_setAssociatedObject(self, @selector(reactTag), reactTag, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}

- (NSNumber *)rootTag
{
return objc_getAssociatedObject(self, _cmd);
}

- (void)setRootTag:(NSNumber *)rootTag
{
objc_setAssociatedObject(self, @selector(rootTag), rootTag, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}

- (NSNumber *)nativeID
{
return objc_getAssociatedObject(self, _cmd);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,8 @@ - (void)removeObserveForTag:(NSInteger)tag

- (UIView *)paperView
{
return [_componentData createViewWithTag:NULL];
// TODO: pass in the right tags?
return [_componentData createViewWithTag:NULL rootTag:NULL];
}

- (void)setProps:(folly::dynamic const &)props forView:(UIView *)view
Expand Down

0 comments on commit 446705d

Please sign in to comment.