Pull CADisplayLink into a separate file
Reviewed By: javache Differential Revision: D3107921 fb-gh-sync-id: 2982043280f925d390e4bebf3884d4762ac62cc6 fbshipit-source-id: 2982043280f925d390e4bebf3884d4762ac62cc6
This commit is contained in:
parent
68918e8773
commit
2115664456
|
@ -14,8 +14,8 @@
|
||||||
#import "RCTBridge+Private.h"
|
#import "RCTBridge+Private.h"
|
||||||
#import "RCTBridgeMethod.h"
|
#import "RCTBridgeMethod.h"
|
||||||
#import "RCTConvert.h"
|
#import "RCTConvert.h"
|
||||||
|
#import "RCTDisplayLink.h"
|
||||||
#import "RCTJSCExecutor.h"
|
#import "RCTJSCExecutor.h"
|
||||||
#import "RCTFrameUpdate.h"
|
|
||||||
#import "RCTJavaScriptLoader.h"
|
#import "RCTJavaScriptLoader.h"
|
||||||
#import "RCTLog.h"
|
#import "RCTLog.h"
|
||||||
#import "RCTModuleData.h"
|
#import "RCTModuleData.h"
|
||||||
|
@ -56,8 +56,7 @@ RCT_EXTERN NSArray<Class> *RCTGetModuleClasses(void);
|
||||||
NSMutableDictionary<NSString *, RCTModuleData *> *_moduleDataByName;
|
NSMutableDictionary<NSString *, RCTModuleData *> *_moduleDataByName;
|
||||||
NSArray<RCTModuleData *> *_moduleDataByID;
|
NSArray<RCTModuleData *> *_moduleDataByID;
|
||||||
NSArray<Class> *_moduleClassesByID;
|
NSArray<Class> *_moduleClassesByID;
|
||||||
CADisplayLink *_jsDisplayLink;
|
RCTDisplayLink *_displayLink;
|
||||||
NSMutableSet<RCTModuleData *> *_frameUpdateObservers;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@synthesize flowID = _flowID;
|
@synthesize flowID = _flowID;
|
||||||
|
@ -81,8 +80,7 @@ RCT_EXTERN NSArray<Class> *RCTGetModuleClasses(void);
|
||||||
_valid = YES;
|
_valid = YES;
|
||||||
_loading = YES;
|
_loading = YES;
|
||||||
_pendingCalls = [NSMutableArray new];
|
_pendingCalls = [NSMutableArray new];
|
||||||
_frameUpdateObservers = [NSMutableSet new];
|
_displayLink = [RCTDisplayLink new];
|
||||||
_jsDisplayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(_jsThreadUpdate:)];
|
|
||||||
|
|
||||||
[RCTBridge setCurrentBridge:self];
|
[RCTBridge setCurrentBridge:self];
|
||||||
|
|
||||||
|
@ -409,20 +407,7 @@ RCT_EXTERN NSArray<Class> *RCTGetModuleClasses(void);
|
||||||
- (void)registerModuleForFrameUpdates:(id<RCTBridgeModule>)module
|
- (void)registerModuleForFrameUpdates:(id<RCTBridgeModule>)module
|
||||||
withModuleData:(RCTModuleData *)moduleData
|
withModuleData:(RCTModuleData *)moduleData
|
||||||
{
|
{
|
||||||
if (![_frameUpdateObservers containsObject:moduleData]) {
|
[_displayLink registerModuleForFrameUpdates:module withModuleData:moduleData];
|
||||||
if ([moduleData.moduleClass conformsToProtocol:@protocol(RCTFrameUpdateObserver)]) {
|
|
||||||
[_frameUpdateObservers addObject:moduleData];
|
|
||||||
// Don't access the module instance via moduleData, as this will cause deadlock
|
|
||||||
id<RCTFrameUpdateObserver> observer = (id<RCTFrameUpdateObserver>)module;
|
|
||||||
__weak typeof(self) weakSelf = self;
|
|
||||||
__weak typeof(_javaScriptExecutor) weakJavaScriptExecutor = _javaScriptExecutor;
|
|
||||||
observer.pauseCallback = ^{
|
|
||||||
[weakJavaScriptExecutor executeBlockOnJavaScriptQueue:^{
|
|
||||||
[weakSelf updateJSDisplayLinkState];
|
|
||||||
}];
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSString *)moduleConfig
|
- (NSString *)moduleConfig
|
||||||
|
@ -441,21 +426,6 @@ RCT_EXTERN NSArray<Class> *RCTGetModuleClasses(void);
|
||||||
}, NULL);
|
}, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)updateJSDisplayLinkState
|
|
||||||
{
|
|
||||||
RCTAssertJSThread();
|
|
||||||
|
|
||||||
BOOL pauseDisplayLink = YES;
|
|
||||||
for (RCTModuleData *moduleData in _frameUpdateObservers) {
|
|
||||||
id<RCTFrameUpdateObserver> observer = (id<RCTFrameUpdateObserver>)moduleData.instance;
|
|
||||||
if (!observer.paused) {
|
|
||||||
pauseDisplayLink = NO;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_jsDisplayLink.paused = pauseDisplayLink;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)injectJSONConfiguration:(NSString *)configJSON
|
- (void)injectJSONConfiguration:(NSString *)configJSON
|
||||||
onComplete:(void (^)(NSError *))onComplete
|
onComplete:(void (^)(NSError *))onComplete
|
||||||
{
|
{
|
||||||
|
@ -492,7 +462,7 @@ RCT_EXTERN NSArray<Class> *RCTGetModuleClasses(void);
|
||||||
|
|
||||||
// Register the display link to start sending js calls after everything is setup
|
// Register the display link to start sending js calls after everything is setup
|
||||||
NSRunLoop *targetRunLoop = [_javaScriptExecutor isKindOfClass:[RCTJSCExecutor class]] ? [NSRunLoop currentRunLoop] : [NSRunLoop mainRunLoop];
|
NSRunLoop *targetRunLoop = [_javaScriptExecutor isKindOfClass:[RCTJSCExecutor class]] ? [NSRunLoop currentRunLoop] : [NSRunLoop mainRunLoop];
|
||||||
[_jsDisplayLink addToRunLoop:targetRunLoop forMode:NSRunLoopCommonModes];
|
[_displayLink addToRunLoop:targetRunLoop];
|
||||||
|
|
||||||
// Perform the state update and notification on the main thread, so we can't run into
|
// Perform the state update and notification on the main thread, so we can't run into
|
||||||
// timing issues with RCTRootView
|
// timing issues with RCTRootView
|
||||||
|
@ -643,8 +613,8 @@ RCT_NOT_IMPLEMENTED(- (instancetype)initWithBundleURL:(__unused NSURL *)bundleUR
|
||||||
|
|
||||||
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
|
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
|
||||||
[_javaScriptExecutor executeBlockOnJavaScriptQueue:^{
|
[_javaScriptExecutor executeBlockOnJavaScriptQueue:^{
|
||||||
[_jsDisplayLink invalidate];
|
[_displayLink invalidate];
|
||||||
_jsDisplayLink = nil;
|
_displayLink = nil;
|
||||||
|
|
||||||
[_javaScriptExecutor invalidate];
|
[_javaScriptExecutor invalidate];
|
||||||
_javaScriptExecutor = nil;
|
_javaScriptExecutor = nil;
|
||||||
|
@ -656,7 +626,6 @@ RCT_NOT_IMPLEMENTED(- (instancetype)initWithBundleURL:(__unused NSURL *)bundleUR
|
||||||
_moduleDataByName = nil;
|
_moduleDataByName = nil;
|
||||||
_moduleDataByID = nil;
|
_moduleDataByID = nil;
|
||||||
_moduleClassesByID = nil;
|
_moduleClassesByID = nil;
|
||||||
_frameUpdateObservers = nil;
|
|
||||||
_pendingCalls = nil;
|
_pendingCalls = nil;
|
||||||
|
|
||||||
if (_flowIDMap != NULL) {
|
if (_flowIDMap != NULL) {
|
||||||
|
@ -1010,30 +979,6 @@ RCT_NOT_IMPLEMENTED(- (instancetype)initWithBundleURL:(__unused NSURL *)bundleUR
|
||||||
return YES;
|
return YES;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)_jsThreadUpdate:(CADisplayLink *)displayLink
|
|
||||||
{
|
|
||||||
RCTAssertJSThread();
|
|
||||||
RCT_PROFILE_BEGIN_EVENT(0, @"-[RCTBatchedBridge _jsThreadUpdate:]", nil);
|
|
||||||
|
|
||||||
RCTFrameUpdate *frameUpdate = [[RCTFrameUpdate alloc] initWithDisplayLink:displayLink];
|
|
||||||
for (RCTModuleData *moduleData in _frameUpdateObservers) {
|
|
||||||
id<RCTFrameUpdateObserver> observer = (id<RCTFrameUpdateObserver>)moduleData.instance;
|
|
||||||
if (!observer.paused) {
|
|
||||||
RCTProfileBeginFlowEvent();
|
|
||||||
[self dispatchBlock:^{
|
|
||||||
RCTProfileEndFlowEvent();
|
|
||||||
[observer didUpdateFrame:frameUpdate];
|
|
||||||
} queue:moduleData.methodQueue];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[self updateJSDisplayLinkState];
|
|
||||||
|
|
||||||
RCTProfileImmediateEvent(0, @"JS Thread Tick", displayLink.timestamp, 'g');
|
|
||||||
|
|
||||||
RCT_PROFILE_END_EVENT(0, @"objc_call", nil);
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)startProfiling
|
- (void)startProfiling
|
||||||
{
|
{
|
||||||
RCTAssertMainThread();
|
RCTAssertMainThread();
|
||||||
|
|
|
@ -0,0 +1,23 @@
|
||||||
|
/**
|
||||||
|
* Copyright (c) 2015-present, Facebook, Inc.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the BSD-style license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree. An additional grant
|
||||||
|
* of patent rights can be found in the PATENTS file in the same directory.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#import <Foundation/Foundation.h>
|
||||||
|
|
||||||
|
@protocol RCTBridgeModule;
|
||||||
|
@class RCTModuleData;
|
||||||
|
|
||||||
|
@interface RCTDisplayLink : NSObject
|
||||||
|
|
||||||
|
- (instancetype)init;
|
||||||
|
- (void)invalidate;
|
||||||
|
- (void)registerModuleForFrameUpdates:(id<RCTBridgeModule>)module
|
||||||
|
withModuleData:(RCTModuleData *)moduleData;
|
||||||
|
- (void)addToRunLoop:(NSRunLoop *)runLoop;
|
||||||
|
|
||||||
|
@end
|
|
@ -0,0 +1,137 @@
|
||||||
|
/**
|
||||||
|
* Copyright (c) 2015-present, Facebook, Inc.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the BSD-style license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree. An additional grant
|
||||||
|
* of patent rights can be found in the PATENTS file in the same directory.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#import "RCTDisplayLink.h"
|
||||||
|
|
||||||
|
#import <Foundation/Foundation.h>
|
||||||
|
#import <QuartzCore/CADisplayLink.h>
|
||||||
|
|
||||||
|
#import "RCTAssert.h"
|
||||||
|
#import "RCTBridgeModule.h"
|
||||||
|
#import "RCTFrameUpdate.h"
|
||||||
|
#import "RCTModuleData.h"
|
||||||
|
#import "RCTProfile.h"
|
||||||
|
|
||||||
|
@implementation RCTDisplayLink
|
||||||
|
{
|
||||||
|
CADisplayLink *_jsDisplayLink;
|
||||||
|
NSMutableSet<RCTModuleData *> *_frameUpdateObservers;
|
||||||
|
NSRunLoop *_runLoop;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (instancetype)init
|
||||||
|
{
|
||||||
|
if ((self = [super init])) {
|
||||||
|
_frameUpdateObservers = [NSMutableSet new];
|
||||||
|
_jsDisplayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(_jsThreadUpdate:)];
|
||||||
|
}
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)registerModuleForFrameUpdates:(id<RCTBridgeModule>)module
|
||||||
|
withModuleData:(RCTModuleData *)moduleData
|
||||||
|
{
|
||||||
|
if ([_frameUpdateObservers containsObject:moduleData] ||
|
||||||
|
![moduleData.moduleClass conformsToProtocol:@protocol(RCTFrameUpdateObserver)]) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
[_frameUpdateObservers addObject:moduleData];
|
||||||
|
// Don't access the module instance via moduleData, as this will cause deadlock
|
||||||
|
id<RCTFrameUpdateObserver> observer = (id<RCTFrameUpdateObserver>)module;
|
||||||
|
__weak typeof(self) weakSelf = self;
|
||||||
|
observer.pauseCallback = ^{
|
||||||
|
typeof(self) strongSelf = weakSelf;
|
||||||
|
if (!strongSelf) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
CFRunLoopRef cfRunLoop = [strongSelf->_runLoop getCFRunLoop];
|
||||||
|
|
||||||
|
if (!_runLoop) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
CFRunLoopPerformBlock(cfRunLoop, kCFRunLoopDefaultMode, ^{
|
||||||
|
[weakSelf updateJSDisplayLinkState];
|
||||||
|
});
|
||||||
|
CFRunLoopWakeUp(cfRunLoop);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)addToRunLoop:(NSRunLoop *)runLoop
|
||||||
|
{
|
||||||
|
_runLoop = runLoop;
|
||||||
|
[_jsDisplayLink addToRunLoop:runLoop forMode:NSRunLoopCommonModes];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)invalidate
|
||||||
|
{
|
||||||
|
[_jsDisplayLink invalidate];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)assertOnRunLoop
|
||||||
|
{
|
||||||
|
RCTAssert(_runLoop == [NSRunLoop currentRunLoop],
|
||||||
|
@"This method must be called on the CADisplayLink run loop");
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)dispatchBlock:(dispatch_block_t)block
|
||||||
|
queue:(dispatch_queue_t)queue
|
||||||
|
{
|
||||||
|
if (queue == RCTJSThread) {
|
||||||
|
block();
|
||||||
|
} else if (queue) {
|
||||||
|
dispatch_async(queue, block);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)_jsThreadUpdate:(CADisplayLink *)displayLink
|
||||||
|
{
|
||||||
|
[self assertOnRunLoop];
|
||||||
|
|
||||||
|
RCT_PROFILE_BEGIN_EVENT(0, @"-[RCTDisplayLink _jsThreadUpdate:]", nil);
|
||||||
|
|
||||||
|
RCTFrameUpdate *frameUpdate = [[RCTFrameUpdate alloc] initWithDisplayLink:displayLink];
|
||||||
|
for (RCTModuleData *moduleData in _frameUpdateObservers) {
|
||||||
|
id<RCTFrameUpdateObserver> observer = (id<RCTFrameUpdateObserver>)moduleData.instance;
|
||||||
|
if (!observer.paused) {
|
||||||
|
RCTProfileBeginFlowEvent();
|
||||||
|
|
||||||
|
[self dispatchBlock:^{
|
||||||
|
RCTProfileEndFlowEvent();
|
||||||
|
[observer didUpdateFrame:frameUpdate];
|
||||||
|
} queue:moduleData.methodQueue];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[self updateJSDisplayLinkState];
|
||||||
|
|
||||||
|
RCTProfileImmediateEvent(0, @"JS Thread Tick", displayLink.timestamp, 'g');
|
||||||
|
|
||||||
|
RCT_PROFILE_END_EVENT(0, @"objc_call", nil);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)updateJSDisplayLinkState
|
||||||
|
{
|
||||||
|
[self assertOnRunLoop];
|
||||||
|
|
||||||
|
BOOL pauseDisplayLink = YES;
|
||||||
|
for (RCTModuleData *moduleData in _frameUpdateObservers) {
|
||||||
|
id<RCTFrameUpdateObserver> observer = (id<RCTFrameUpdateObserver>)moduleData.instance;
|
||||||
|
if (!observer.paused) {
|
||||||
|
pauseDisplayLink = NO;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_jsDisplayLink.paused = pauseDisplayLink;
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
Loading…
Reference in New Issue