From 048a9ab10c0ae7ab85679eca39a24f0dc5640dfd Mon Sep 17 00:00:00 2001 From: Steffen Matthischke Date: Fri, 14 Jul 2017 20:54:46 -0700 Subject: [PATCH] RCTScrollEvent: get all required values injected rather than accessing the scroll view Summary: This PR fixes #15006 by removing all UI API calls from RCTScrollEvent. `-[RCTScrollEvent arguments]` can now be called from a background thread. The Main Thread Checker of Xcode 9 will not any longer produce runtime issues when calling this method. 1. create a React Native (version: this PR) project with a scroll view 2. open it in Xcode 9 3. launch it 4. scroll the scroll view 5. observe the runtime issues in Xcode. There should not contain "UI API called from background thread"-issues. I verified my changes on this branch: https://github.com/HeEAaD/Demo-ReactNative-UI-not-on-main-thread/tree/fix Closes https://github.com/facebook/react-native/pull/15008 Differential Revision: D5424734 Pulled By: shergin fbshipit-source-id: 56beec2d7603ea6782d55622567509f3758a4517 --- React/Views/RCTScrollView.m | 58 ++++++++++++++++++++++++++----------- 1 file changed, 41 insertions(+), 17 deletions(-) diff --git a/React/Views/RCTScrollView.m b/React/Views/RCTScrollView.m index 0035da12872..9c4be9d6ff5 100644 --- a/React/Views/RCTScrollView.m +++ b/React/Views/RCTScrollView.m @@ -27,7 +27,11 @@ - (instancetype)initWithEventName:(NSString *)eventName reactTag:(NSNumber *)reactTag - scrollView:(UIScrollView *)scrollView + scrollViewContentOffset:(CGPoint)scrollViewContentOffset + scrollViewContentInset:(UIEdgeInsets)scrollViewContentInset + scrollViewContentSize:(CGSize)scrollViewContentSize + scrollViewFrame:(CGRect)scrollViewFrame + scrollViewZoomScale:(CGFloat)scrollViewZoomScale userData:(NSDictionary *)userData coalescingKey:(uint16_t)coalescingKey NS_DESIGNATED_INITIALIZER; @@ -35,7 +39,11 @@ @implementation RCTScrollEvent { - UIScrollView *_scrollView; + CGPoint _scrollViewContentOffset; + UIEdgeInsets _scrollViewContentInset; + CGSize _scrollViewContentSize; + CGRect _scrollViewFrame; + CGFloat _scrollViewZoomScale; NSDictionary *_userData; uint16_t _coalescingKey; } @@ -45,7 +53,11 @@ - (instancetype)initWithEventName:(NSString *)eventName reactTag:(NSNumber *)reactTag - scrollView:(UIScrollView *)scrollView + scrollViewContentOffset:(CGPoint)scrollViewContentOffset + scrollViewContentInset:(UIEdgeInsets)scrollViewContentInset + scrollViewContentSize:(CGSize)scrollViewContentSize + scrollViewFrame:(CGRect)scrollViewFrame + scrollViewZoomScale:(CGFloat)scrollViewZoomScale userData:(NSDictionary *)userData coalescingKey:(uint16_t)coalescingKey { @@ -54,7 +66,11 @@ if ((self = [super init])) { _eventName = [eventName copy]; _viewTag = reactTag; - _scrollView = scrollView; + _scrollViewContentOffset = scrollViewContentOffset; + _scrollViewContentInset = scrollViewContentInset; + _scrollViewContentSize = scrollViewContentSize; + _scrollViewFrame = scrollViewFrame; + _scrollViewZoomScale = scrollViewZoomScale; _userData = userData; _coalescingKey = coalescingKey; } @@ -72,24 +88,24 @@ RCT_NOT_IMPLEMENTED(- (instancetype)init) { NSDictionary *body = @{ @"contentOffset": @{ - @"x": @(_scrollView.contentOffset.x), - @"y": @(_scrollView.contentOffset.y) + @"x": @(_scrollViewContentOffset.x), + @"y": @(_scrollViewContentOffset.y) }, @"contentInset": @{ - @"top": @(_scrollView.contentInset.top), - @"left": @(_scrollView.contentInset.left), - @"bottom": @(_scrollView.contentInset.bottom), - @"right": @(_scrollView.contentInset.right) + @"top": @(_scrollViewContentInset.top), + @"left": @(_scrollViewContentInset.left), + @"bottom": @(_scrollViewContentInset.bottom), + @"right": @(_scrollViewContentInset.right) }, @"contentSize": @{ - @"width": @(_scrollView.contentSize.width), - @"height": @(_scrollView.contentSize.height) + @"width": @(_scrollViewContentSize.width), + @"height": @(_scrollViewContentSize.height) }, @"layoutMeasurement": @{ - @"width": @(_scrollView.frame.size.width), - @"height": @(_scrollView.frame.size.height) + @"width": @(_scrollViewFrame.size.width), + @"height": @(_scrollViewFrame.size.height) }, - @"zoomScale": @(_scrollView.zoomScale ?: 1), + @"zoomScale": @(_scrollViewZoomScale ?: 1), }; if (_userData) { @@ -893,7 +909,11 @@ RCT_SET_AND_PRESERVE_OFFSET(setScrollIndicatorInsets, scrollIndicatorInsets, UIE } RCTScrollEvent *scrollEvent = [[RCTScrollEvent alloc] initWithEventName:eventName reactTag:self.reactTag - scrollView:scrollView + scrollViewContentOffset:scrollView.contentOffset + scrollViewContentInset:scrollView.contentInset + scrollViewContentSize:scrollView.contentSize + scrollViewFrame:scrollView.frame + scrollViewZoomScale:scrollView.zoomScale userData:userData coalescingKey:_coalescingKey]; [_eventDispatcher sendEvent:scrollEvent]; @@ -909,7 +929,11 @@ RCT_SET_AND_PRESERVE_OFFSET(setScrollIndicatorInsets, scrollIndicatorInsets, UIE NSString *eventName = NSStringFromSelector(@selector(onScroll)); RCTScrollEvent *fakeScrollEvent = [[RCTScrollEvent alloc] initWithEventName:eventName reactTag:reactTag - scrollView:nil + scrollViewContentOffset:CGPointZero + scrollViewContentInset:UIEdgeInsetsZero + scrollViewContentSize:CGSizeZero + scrollViewFrame:CGRectZero + scrollViewZoomScale:0 userData:nil coalescingKey:0]; [self sendEvent:fakeScrollEvent];