mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
[ReactNative] Use a single DisplayLink held by the bridge
This commit is contained in:
@@ -10,6 +10,7 @@
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
#import "RCTBridgeModule.h"
|
||||
#import "RCTFrameUpdate.h"
|
||||
#import "RCTInvalidating.h"
|
||||
#import "RCTJavaScriptExecutor.h"
|
||||
|
||||
@@ -122,4 +123,14 @@ static const char *__rct_import_##module##_##method##__ = #module"."#method;
|
||||
*/
|
||||
- (void)reload;
|
||||
|
||||
/**
|
||||
* Add a new observer that will be called on every screen refresh
|
||||
*/
|
||||
- (void)addFrameUpdateObserver:(id<RCTFrameUpdateObserver>)observer;
|
||||
|
||||
/**
|
||||
* Stop receiving screen refresh updates for the given observer
|
||||
*/
|
||||
- (void)removeFrameUpdateObserver:(id<RCTFrameUpdateObserver>)observer;
|
||||
|
||||
@end
|
||||
|
||||
@@ -677,6 +677,73 @@ static NSDictionary *RCTLocalModulesConfig()
|
||||
return localModules;
|
||||
}
|
||||
|
||||
@interface RCTDisplayLink : NSObject <RCTInvalidating>
|
||||
|
||||
- (instancetype)initWithBridge:(RCTBridge *)bridge NS_DESIGNATED_INITIALIZER;
|
||||
|
||||
@end
|
||||
|
||||
@interface RCTBridge (RCTDisplayLink)
|
||||
|
||||
- (void)_update:(CADisplayLink *)displayLink;
|
||||
|
||||
@end
|
||||
|
||||
@implementation RCTDisplayLink
|
||||
{
|
||||
__weak RCTBridge *_bridge;
|
||||
CADisplayLink *_displayLink;
|
||||
}
|
||||
|
||||
- (instancetype)initWithBridge:(RCTBridge *)bridge
|
||||
{
|
||||
if ((self = [super init])) {
|
||||
_bridge = bridge;
|
||||
_displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(_update:)];
|
||||
[_displayLink addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (BOOL)isValid
|
||||
{
|
||||
return _displayLink != nil;
|
||||
}
|
||||
|
||||
- (void)invalidate
|
||||
{
|
||||
if (self.isValid) {
|
||||
[_displayLink invalidate];
|
||||
_displayLink = nil;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)_update:(CADisplayLink *)displayLink
|
||||
{
|
||||
[_bridge _update:displayLink];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@interface RCTFrameUpdate (Private)
|
||||
|
||||
- (instancetype)initWithDisplayLink:(CADisplayLink *)displayLink;
|
||||
|
||||
@end
|
||||
|
||||
@implementation RCTFrameUpdate
|
||||
|
||||
- (instancetype)initWithDisplayLink:(CADisplayLink *)displayLink
|
||||
{
|
||||
if ((self = [super init])) {
|
||||
_timestamp = displayLink.timestamp;
|
||||
_deltaTime = displayLink.duration;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation RCTBridge
|
||||
{
|
||||
RCTSparseArray *_modulesByID;
|
||||
@@ -685,6 +752,8 @@ static NSDictionary *RCTLocalModulesConfig()
|
||||
Class _executorClass;
|
||||
NSURL *_bundleURL;
|
||||
RCTBridgeModuleProviderBlock _moduleProvider;
|
||||
RCTDisplayLink *_displayLink;
|
||||
NSMutableSet *_frameUpdateObservers;
|
||||
BOOL _loading;
|
||||
}
|
||||
|
||||
@@ -711,6 +780,8 @@ static id<RCTJavaScriptExecutor> _latestJSExecutor;
|
||||
_latestJSExecutor = _javaScriptExecutor;
|
||||
_eventDispatcher = [[RCTEventDispatcher alloc] initWithBridge:self];
|
||||
_shadowQueue = dispatch_queue_create("com.facebook.React.ShadowQueue", DISPATCH_QUEUE_SERIAL);
|
||||
_displayLink = [[RCTDisplayLink alloc] initWithBridge:self];
|
||||
_frameUpdateObservers = [[NSMutableSet alloc] init];
|
||||
|
||||
// Register passed-in module instances
|
||||
NSMutableDictionary *preregisteredModules = [[NSMutableDictionary alloc] init];
|
||||
@@ -891,6 +962,9 @@ static id<RCTJavaScriptExecutor> _latestJSExecutor;
|
||||
[_javaScriptExecutor invalidate];
|
||||
_javaScriptExecutor = nil;
|
||||
|
||||
[_displayLink invalidate];
|
||||
_frameUpdateObservers = nil;
|
||||
|
||||
// Invalidate modules
|
||||
for (id target in _modulesByID.allObjects) {
|
||||
if ([target respondsToSelector:@selector(invalidate)]) {
|
||||
@@ -1075,6 +1149,26 @@ static id<RCTJavaScriptExecutor> _latestJSExecutor;
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (void)_update:(CADisplayLink *)displayLink
|
||||
{
|
||||
RCTFrameUpdate *frameUpdate = [[RCTFrameUpdate alloc] initWithDisplayLink:displayLink];
|
||||
for (id<RCTFrameUpdateObserver> observer in _frameUpdateObservers) {
|
||||
if (![observer respondsToSelector:@selector(isPaused)] || ![observer isPaused]) {
|
||||
[observer didUpdateFrame:frameUpdate];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)addFrameUpdateObserver:(id<RCTFrameUpdateObserver>)observer
|
||||
{
|
||||
[_frameUpdateObservers addObject:observer];
|
||||
}
|
||||
|
||||
- (void)removeFrameUpdateObserver:(id<RCTFrameUpdateObserver>)observer
|
||||
{
|
||||
[_frameUpdateObservers removeObject:observer];
|
||||
}
|
||||
|
||||
- (void)reload
|
||||
{
|
||||
if (!_loading) {
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Interface containing the information about the last screen refresh.
|
||||
*/
|
||||
@interface RCTFrameUpdate : NSObject
|
||||
|
||||
/**
|
||||
* Timestamp for the actual screen refresh
|
||||
*/
|
||||
@property (nonatomic, readonly) NSTimeInterval timestamp;
|
||||
|
||||
/**
|
||||
* Time since the last frame update ( >= 16.6ms )
|
||||
*/
|
||||
@property (nonatomic, readonly) NSTimeInterval deltaTime;
|
||||
|
||||
@end
|
||||
|
||||
/**
|
||||
* Protocol that must be implemented for subscribing to display refreshes (DisplayLink updates)
|
||||
*/
|
||||
@protocol RCTFrameUpdateObserver <NSObject>
|
||||
|
||||
/**
|
||||
* Method called on every screen refresh (if paused != YES)
|
||||
*/
|
||||
- (void)didUpdateFrame:(RCTFrameUpdate *)update;
|
||||
|
||||
@optional
|
||||
|
||||
/**
|
||||
* Synthesize and set to true to pause the calls to -[didUpdateFrame:]
|
||||
*/
|
||||
@property (nonatomic, assign, getter=isPaused) BOOL paused;
|
||||
|
||||
@end
|
||||
Reference in New Issue
Block a user