diff --git a/packages/react-native/React/Base/RCTBridge+Private.h b/packages/react-native/React/Base/RCTBridge+Private.h index 3a5141fe47a7..d01973195a1b 100644 --- a/packages/react-native/React/Base/RCTBridge+Private.h +++ b/packages/react-native/React/Base/RCTBridge+Private.h @@ -84,12 +84,6 @@ RCT_EXTERN void RCTRegisterModule(Class); */ - (void)start; -/** - * Used by RCTModuleData to register the module for frame updates after it is - * lazily initialized. - */ -- (void)registerModuleForFrameUpdates:(id)module withModuleData:(RCTModuleData *)moduleData; - /** * Dispatch work to a module's queue - this is also supports the fake RCTJSThread * queue. Exposed for the RCTProfiler diff --git a/packages/react-native/React/Base/RCTDisplayLink.h b/packages/react-native/React/Base/RCTDisplayLink.h index a8e0c10cfebb..87c1d6b65749 100644 --- a/packages/react-native/React/Base/RCTDisplayLink.h +++ b/packages/react-native/React/Base/RCTDisplayLink.h @@ -7,23 +7,13 @@ #import -@protocol RCTBridgeModule; -@class RCTModuleData; - -@protocol RCTDisplayLinkModuleHolder -- (id)instance; -- (Class)moduleClass; -- (dispatch_queue_t)methodQueue; -@end +@protocol RCTFrameUpdateObserver; @interface RCTDisplayLink : NSObject - (instancetype)init; - (void)invalidate; -- (void)registerModuleForFrameUpdates:(id)module - withModuleHolder:(id)moduleHolder - __attribute__((deprecated( - "registerModuleForFrameUpdates is part of the legacy architecture and will be removed in a future React Native release."))); +- (void)registerTimingForFrameUpdates:(id)module; - (void)addToRunLoop:(NSRunLoop *)runLoop; @end diff --git a/packages/react-native/React/Base/RCTDisplayLink.m b/packages/react-native/React/Base/RCTDisplayLink.m index de7c8700f3e5..4280aa3164f6 100644 --- a/packages/react-native/React/Base/RCTDisplayLink.m +++ b/packages/react-native/React/Base/RCTDisplayLink.m @@ -11,9 +11,7 @@ #import #import "RCTAssert.h" -#import "RCTBridgeModule.h" #import "RCTFrameUpdate.h" -#import "RCTModuleData.h" #import "RCTProfile.h" #define RCTAssertRunLoop() \ @@ -21,7 +19,7 @@ @implementation RCTDisplayLink { CADisplayLink *_jsDisplayLink; - NSMutableSet> *_frameUpdateObservers; + NSMutableSet> *_frameUpdateObservers; NSRunLoop *_runLoop; } @@ -35,18 +33,11 @@ - (instancetype)init return self; } -- (void)registerModuleForFrameUpdates:(id)module - withModuleHolder:(id)moduleHolder +- (void)registerTimingForFrameUpdates:(id)timing { - if (![moduleHolder.moduleClass conformsToProtocol:@protocol(RCTFrameUpdateObserver)] || - [_frameUpdateObservers containsObject:moduleHolder]) { - return; - } - - [_frameUpdateObservers addObject:moduleHolder]; + [_frameUpdateObservers addObject:timing]; - // Don't access the module instance via moduleHolder, as this will cause deadlock - id observer = (id)module; + id observer = timing; __weak typeof(self) weakSelf = self; observer.pauseCallback = ^{ typeof(self) strongSelf = weakSelf; @@ -97,8 +88,7 @@ - (void)dealloc - (void)invalidate { // ensure observer callbacks do not hold a reference to weak self via pauseCallback - for (id moduleHolder in _frameUpdateObservers) { - id observer = (id)moduleHolder.instance; + for (id observer in _frameUpdateObservers) { [observer setPauseCallback:nil]; } [_frameUpdateObservers removeAllObjects]; // just to be explicit @@ -106,36 +96,18 @@ - (void)invalidate [_jsDisplayLink invalidate]; } -- (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 { RCTAssertRunLoop(); RCT_PROFILE_BEGIN_EVENT(RCTProfileTagAlways, @"-[RCTDisplayLink _jsThreadUpdate:]", nil); + // This always runs on the JS thread run loop, which is the queue the frame + // update observers expect their callbacks on, so dispatch inline. RCTFrameUpdate *frameUpdate = [[RCTFrameUpdate alloc] initWithDisplayLink:displayLink]; - for (id moduleHolder in _frameUpdateObservers) { - id observer = (id)moduleHolder.instance; + for (id observer in _frameUpdateObservers) { if (!observer.paused) { - if (moduleHolder.methodQueue) { - RCTProfileBeginFlowEvent(); - [self - dispatchBlock:^{ - RCTProfileEndFlowEvent(); - [observer didUpdateFrame:frameUpdate]; - } - queue:moduleHolder.methodQueue]; - } else { - [observer didUpdateFrame:frameUpdate]; - } + [observer didUpdateFrame:frameUpdate]; } } @@ -151,8 +123,7 @@ - (void)updateJSDisplayLinkState RCTAssertRunLoop(); BOOL pauseDisplayLink = YES; - for (id moduleHolder in _frameUpdateObservers) { - id observer = (id)moduleHolder.instance; + for (id observer in _frameUpdateObservers) { if (!observer.paused) { pauseDisplayLink = NO; break; diff --git a/packages/react-native/React/CoreModules/CoreModulesPlugins.h b/packages/react-native/React/CoreModules/CoreModulesPlugins.h index e62d4d157bb0..a9842abde418 100644 --- a/packages/react-native/React/CoreModules/CoreModulesPlugins.h +++ b/packages/react-native/React/CoreModules/CoreModulesPlugins.h @@ -49,7 +49,6 @@ Class RCTPlatformCls(void) __attribute__((used)); Class RCTRedBoxCls(void) __attribute__((used)); Class RCTSourceCodeCls(void) __attribute__((used)); Class RCTStatusBarManagerCls(void) __attribute__((used)); -Class RCTTimingCls(void) __attribute__((used)); Class RCTWebSocketModuleCls(void) __attribute__((used)); Class RCTBlobManagerCls(void) __attribute__((used)); diff --git a/packages/react-native/React/CoreModules/CoreModulesPlugins.mm b/packages/react-native/React/CoreModules/CoreModulesPlugins.mm index f0844ee8afdf..005f75065a63 100644 --- a/packages/react-native/React/CoreModules/CoreModulesPlugins.mm +++ b/packages/react-native/React/CoreModules/CoreModulesPlugins.mm @@ -100,10 +100,6 @@ Class RCTCoreModulesClassProvider(const char *name) return RCTStatusBarManagerCls(); } - if (name == "Timing"sv) { - return RCTTimingCls(); - } - if (name == "WebSocketModule"sv) { return RCTWebSocketModuleCls(); } diff --git a/packages/react-native/React/CoreModules/RCTTiming.h b/packages/react-native/React/CoreModules/RCTTiming.h index 2a7519afb1b6..6b2fe638f3af 100644 --- a/packages/react-native/React/CoreModules/RCTTiming.h +++ b/packages/react-native/React/CoreModules/RCTTiming.h @@ -7,7 +7,6 @@ #import -#import #import #import #import @@ -22,7 +21,7 @@ NS_ASSUME_NONNULL_BEGIN @end -@interface RCTTiming : NSObject +@interface RCTTiming : NSObject - (instancetype)initWithDelegate:(id)delegate; - (void)createTimerForNextFrame:(NSNumber *)callbackID diff --git a/packages/react-native/React/CoreModules/RCTTiming.mm b/packages/react-native/React/CoreModules/RCTTiming.mm index 14ee7844c7fe..52a3dd7b3c08 100644 --- a/packages/react-native/React/CoreModules/RCTTiming.mm +++ b/packages/react-native/React/CoreModules/RCTTiming.mm @@ -7,17 +7,11 @@ #import "RCTTiming.h" -#import - #import -#import -#import #import #import #import -#import "CoreModulesPlugins.h" - static const NSTimeInterval kMinimumSleepInterval = 1; // These timing contants should be kept in sync with the ones in `JSTimers.js`. @@ -82,7 +76,7 @@ @implementation _RCTTimingProxy { + (instancetype)proxyWithTarget:(id)target { _RCTTimingProxy *proxy = [self new]; - if (proxy) { + if (proxy != nullptr) { proxy->_target = target; } return proxy; @@ -103,12 +97,9 @@ @implementation RCTTiming { id _timingDelegate; } -@synthesize bridge = _bridge; @synthesize paused = _paused; @synthesize pauseCallback = _pauseCallback; -RCT_EXPORT_MODULE() - - (instancetype)initWithDelegate:(id)delegate { if (self = [super init]) { @@ -165,15 +156,9 @@ - (void)dealloc [_sleepTimer invalidate]; } -- (dispatch_queue_t)methodQueue -{ - return RCTJSThread; -} - - (void)invalidate { [self stopTimers]; - _bridge = nil; _timingDelegate = nil; } @@ -220,7 +205,7 @@ - (void)stopTimers - (void)startTimers { - if ((!_bridge && !_timingDelegate) || _inBackground || ![self hasPendingTimers]) { + if ((!_timingDelegate) || _inBackground || ![self hasPendingTimers]) { return; } @@ -259,11 +244,7 @@ - (void)didUpdateFrame:(RCTFrameUpdate *)update NSArray *sortedTimers = [[timersToCall sortedArrayUsingComparator:^(_RCTTimer *a, _RCTTimer *b) { return [a.target compare:b.target]; }] valueForKey:@"callbackID"]; - if (_bridge) { - [_bridge enqueueJSCall:@"JSTimers" method:@"callTimers" args:@[ sortedTimers ] completion:NULL]; - } else { - [_timingDelegate callTimers:sortedTimers]; - } + [_timingDelegate callTimers:sortedTimers]; } for (_RCTTimer *timer in timersToCall) { @@ -282,23 +263,19 @@ - (void)didUpdateFrame:(RCTFrameUpdate *)update if (kFrameDuration - frameElapsed >= kIdleCallbackFrameDeadline) { NSTimeInterval currentTimestamp = [[NSDate date] timeIntervalSince1970]; NSNumber *absoluteFrameStartMS = @((currentTimestamp - frameElapsed) * 1000); - if (_bridge) { - [_bridge enqueueJSCall:@"JSTimers" method:@"callIdleCallbacks" args:@[ absoluteFrameStartMS ] completion:NULL]; - } else { - [_timingDelegate callIdleCallbacks:absoluteFrameStartMS]; - } + [_timingDelegate callIdleCallbacks:absoluteFrameStartMS]; } } // Switch to a paused state only if we didn't call any timer this frame, so if // in response to this timer another timer is scheduled, we don't pause and unpause // the displaylink frivolously. - NSUInteger timerCount; + NSUInteger timerCount = 0; @synchronized(_timers) { timerCount = _timers.count; } if (_inBackground) { - if (timerCount) { + if (timerCount != 0u) { [self scheduleSleepTimer:nextScheduledTarget]; } } else if (!_sendIdleEvents && timersToCall.count == 0) { @@ -318,7 +295,7 @@ - (void)didUpdateFrame:(RCTFrameUpdate *)update - (void)scheduleSleepTimer:(NSDate *)sleepTarget { @synchronized(self) { - if (!_sleepTimer || !_sleepTimer.valid) { + if ((_sleepTimer == nullptr) || !_sleepTimer.valid) { _sleepTimer = [[NSTimer alloc] initWithFireDate:sleepTarget interval:0 target:[_RCTTimingProxy proxyWithTarget:self] @@ -343,35 +320,6 @@ - (void)timerDidFire } } -/** - * A method used for asynchronously creating a timer. If the timer has already expired, - * (based on the provided jsSchedulingTime) then it will be immediately invoked. - * - * There's a small difference between the time when we call - * setTimeout/setInterval/requestAnimation frame and the time it actually makes - * it here. This is important and needs to be taken into account when - * calculating the timer's target time. We calculate this by passing in - * Date.now() from JS and then subtracting that from the current time here. - */ -RCT_EXPORT_METHOD( - createTimer : (double)callbackID duration : (NSTimeInterval)jsDuration jsSchedulingTime : (double) - jsSchedulingTime repeats : (BOOL)repeats) -{ - NSNumber *callbackIdObjc = [NSNumber numberWithDouble:callbackID]; - NSDate *schedulingTime = [RCTConvert NSDate:[NSNumber numberWithDouble:jsSchedulingTime]]; - if (jsDuration == 0 && repeats == NO) { - // For super fast, one-off timers, just enqueue them immediately rather than waiting a frame. - if (_bridge) { - [_bridge _immediatelyCallTimer:callbackIdObjc]; - } else { - [_timingDelegate immediatelyCallTimer:callbackIdObjc]; - } - return; - } - - [self createTimerForNextFrame:callbackIdObjc duration:jsDuration jsSchedulingTime:schedulingTime repeats:repeats]; -} - /** * A method used for synchronously creating a timer. The timer will not be invoked until the * next frame, regardless of whether it has already expired (i.e. jsSchedulingTime is 0). @@ -407,29 +355,14 @@ - (void)createTimerForNextFrame:(nonnull NSNumber *)callbackID } } -RCT_EXPORT_METHOD(deleteTimer : (double)timerID) +- (void)deleteTimer:(double)timerID { @synchronized(_timers) { - [_timers removeObjectForKey:[NSNumber numberWithDouble:timerID]]; + [_timers removeObjectForKey:@(timerID)]; } if (![self hasPendingTimers]) { [self stopTimers]; } } -RCT_EXPORT_METHOD(setSendIdleEvents : (BOOL)sendIdleEvents) -{ - _sendIdleEvents = sendIdleEvents; - if (sendIdleEvents) { - [self startTimers]; - } else if (![self hasPendingTimers]) { - [self stopTimers]; - } -} - @end - -Class RCTTimingCls(void) -{ - return RCTTiming.class; -} diff --git a/packages/react-native/ReactCommon/react/runtime/platform/ios/ReactCommon/RCTInstance.mm b/packages/react-native/ReactCommon/react/runtime/platform/ios/ReactCommon/RCTInstance.mm index 036551395323..057565d7ae8f 100644 --- a/packages/react-native/ReactCommon/react/runtime/platform/ios/ReactCommon/RCTInstance.mm +++ b/packages/react-native/ReactCommon/react/runtime/platform/ios/ReactCommon/RCTInstance.mm @@ -74,37 +74,6 @@ void RCTInstanceSetRuntimeDiagnosticFlags(NSString *flags) sRuntimeDiagnosticFlags = [flags copy]; } -__attribute__((deprecated( - "RCTBridgelessDisplayLinkModuleHolder is part of the legacy architecture and will be removed in a future React Native release."))) -@interface RCTBridgelessDisplayLinkModuleHolder : NSObject -- (instancetype)initWithModule:(id)module; -@end - -@implementation RCTBridgelessDisplayLinkModuleHolder { - id _module; -} -- (instancetype)initWithModule:(id)module -{ - _module = module; - return self; -} - -- (id)instance -{ - return _module; -} - -- (Class)moduleClass -{ - return [_module class]; -} - -- (dispatch_queue_t)methodQueue -{ - return _module.methodQueue; -} -@end - @interface RCTInstance () @end @@ -462,12 +431,8 @@ - (void)_start [strongSelf->_delegate instance:strongSelf didInitializeRuntime:runtime]; -// Set up Display Link -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wdeprecated-declarations" - id moduleHolder = [[RCTBridgelessDisplayLinkModuleHolder alloc] initWithModule:timing]; - [strongSelf->_displayLink registerModuleForFrameUpdates:timing withModuleHolder:moduleHolder]; -#pragma clang diagnostic pop + // Set up Display Link + [strongSelf->_displayLink registerTimingForFrameUpdates:timing]; [strongSelf->_displayLink addToRunLoop:[NSRunLoop currentRunLoop]]; // Attempt to load bundle synchronously, fallback to asynchronously. diff --git a/scripts/cxx-api/api-snapshots/ReactAppleDebugCxx.api b/scripts/cxx-api/api-snapshots/ReactAppleDebugCxx.api index 026291c9bf6d..e054d8f78edb 100644 --- a/scripts/cxx-api/api-snapshots/ReactAppleDebugCxx.api +++ b/scripts/cxx-api/api-snapshots/ReactAppleDebugCxx.api @@ -1027,7 +1027,7 @@ interface RCTDisplayLink : public NSObject { public virtual instancetype init(); public virtual void addToRunLoop:(NSRunLoop* runLoop); public virtual void invalidate(); - public virtual void registerModuleForFrameUpdates:withModuleHolder:(id module, id moduleHolder); + public virtual void registerTimingForFrameUpdates:(id module); } interface RCTDisplayWeakRefreshable : public NSObject { @@ -1966,7 +1966,7 @@ interface RCTThirdPartyComponentsProvider : public NSObject { public virtual static NSDictionary>* thirdPartyFabricComponents(); } -interface RCTTiming : public NSObject { +interface RCTTiming : public NSObject { public virtual instancetype initWithDelegate:(id delegate); public virtual void createTimerForNextFrame:duration:jsSchedulingTime:repeats:(NSNumber* callbackID, NSTimeInterval jsDuration, _Nullable NSDate* jsSchedulingTime, BOOL repeats); public virtual void deleteTimer:(double timerID); @@ -2760,12 +2760,6 @@ protocol RCTDevSettingsInspectable : public NSObject { public @property (assign) BOOL isInspectable; } -protocol RCTDisplayLinkModuleHolder { - public virtual Class moduleClass(); - public virtual dispatch_queue_t methodQueue(); - public virtual id instance(); -} - protocol RCTDisplayRefreshable { public virtual void displayDidRefresh:(CADisplayLink* displayLink); } diff --git a/scripts/cxx-api/api-snapshots/ReactAppleNewarchCxx.api b/scripts/cxx-api/api-snapshots/ReactAppleNewarchCxx.api index 3cc8ba4fe000..5de223b7f928 100644 --- a/scripts/cxx-api/api-snapshots/ReactAppleNewarchCxx.api +++ b/scripts/cxx-api/api-snapshots/ReactAppleNewarchCxx.api @@ -1025,7 +1025,7 @@ interface RCTDisplayLink : public NSObject { public virtual instancetype init(); public virtual void addToRunLoop:(NSRunLoop* runLoop); public virtual void invalidate(); - public virtual void registerModuleForFrameUpdates:withModuleHolder:(id module, id moduleHolder); + public virtual void registerTimingForFrameUpdates:(id module); } interface RCTDisplayWeakRefreshable : public NSObject { @@ -1955,7 +1955,7 @@ interface RCTThirdPartyComponentsProvider : public NSObject { public virtual static NSDictionary>* thirdPartyFabricComponents(); } -interface RCTTiming : public NSObject { +interface RCTTiming : public NSObject { public virtual instancetype initWithDelegate:(id delegate); public virtual void createTimerForNextFrame:duration:jsSchedulingTime:repeats:(NSNumber* callbackID, NSTimeInterval jsDuration, _Nullable NSDate* jsSchedulingTime, BOOL repeats); public virtual void deleteTimer:(double timerID); @@ -2748,12 +2748,6 @@ protocol RCTDevSettingsInspectable : public NSObject { public @property (assign) BOOL isInspectable; } -protocol RCTDisplayLinkModuleHolder { - public virtual Class moduleClass(); - public virtual dispatch_queue_t methodQueue(); - public virtual id instance(); -} - protocol RCTDisplayRefreshable { public virtual void displayDidRefresh:(CADisplayLink* displayLink); } diff --git a/scripts/cxx-api/api-snapshots/ReactAppleReleaseCxx.api b/scripts/cxx-api/api-snapshots/ReactAppleReleaseCxx.api index c347a55a5355..0e54c5caca2c 100644 --- a/scripts/cxx-api/api-snapshots/ReactAppleReleaseCxx.api +++ b/scripts/cxx-api/api-snapshots/ReactAppleReleaseCxx.api @@ -1027,7 +1027,7 @@ interface RCTDisplayLink : public NSObject { public virtual instancetype init(); public virtual void addToRunLoop:(NSRunLoop* runLoop); public virtual void invalidate(); - public virtual void registerModuleForFrameUpdates:withModuleHolder:(id module, id moduleHolder); + public virtual void registerTimingForFrameUpdates:(id module); } interface RCTDisplayWeakRefreshable : public NSObject { @@ -1966,7 +1966,7 @@ interface RCTThirdPartyComponentsProvider : public NSObject { public virtual static NSDictionary>* thirdPartyFabricComponents(); } -interface RCTTiming : public NSObject { +interface RCTTiming : public NSObject { public virtual instancetype initWithDelegate:(id delegate); public virtual void createTimerForNextFrame:duration:jsSchedulingTime:repeats:(NSNumber* callbackID, NSTimeInterval jsDuration, _Nullable NSDate* jsSchedulingTime, BOOL repeats); public virtual void deleteTimer:(double timerID); @@ -2760,12 +2760,6 @@ protocol RCTDevSettingsInspectable : public NSObject { public @property (assign) BOOL isInspectable; } -protocol RCTDisplayLinkModuleHolder { - public virtual Class moduleClass(); - public virtual dispatch_queue_t methodQueue(); - public virtual id instance(); -} - protocol RCTDisplayRefreshable { public virtual void displayDidRefresh:(CADisplayLink* displayLink); }