forked from facebook/react-native
-
Notifications
You must be signed in to change notification settings - Fork 15
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
6 changed files
with
234 additions
and
8 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
// | ||
// RCTDisplayLink.h | ||
// React | ||
// | ||
// Created by Stanislav Vishnevskiy on 6/8/15. | ||
// Copyright (c) 2015 Facebook. All rights reserved. | ||
// | ||
|
||
#import <QuartzCore/CABase.h> | ||
#import <Foundation/NSObject.h> | ||
|
||
@class NSString, NSRunLoop; | ||
|
||
@interface DCDDisplayLink : NSObject | ||
|
||
/* Create a new display link object for the main display. It will | ||
* invoke the method called 'sel' on 'target', the method has the | ||
* signature '(void)selector:(CADisplayLink *)sender'. */ | ||
|
||
+ (DCDDisplayLink *)displayLinkWithTarget:(id)target selector:(SEL)sel; | ||
|
||
/* Adds the receiver to the given run-loop and mode. Unless paused, it | ||
* will fire every vsync until removed. Each object may only be added | ||
* to a single run-loop, but it may be added in multiple modes at once. | ||
* While added to a run-loop it will implicitly be retained. */ | ||
|
||
- (void)addToRunLoop:(NSRunLoop *)runloop forMode:(NSString *)mode; | ||
|
||
/* Removes the receiver from the given mode of the runloop. This will | ||
* implicitly release it when removed from the last mode it has been | ||
* registered for. */ | ||
|
||
- (void)removeFromRunLoop:(NSRunLoop *)runloop forMode:(NSString *)mode; | ||
|
||
/* Removes the object from all runloop modes (releasing the receiver if | ||
* it has been implicitly retained) and releases the 'target' object. */ | ||
|
||
- (void)invalidate; | ||
|
||
/* The current time, and duration of the display frame associated with | ||
* the most recent target invocation. Time is represented using the | ||
* normal Core Animation conventions, i.e. Mach host time converted to | ||
* seconds. */ | ||
|
||
@property(readonly, nonatomic) CFTimeInterval timestamp; | ||
@property(readonly, nonatomic) CFTimeInterval duration; | ||
|
||
/* When true the object is prevented from firing. Initial state is | ||
* false. */ | ||
|
||
@property(getter=isPaused, nonatomic) BOOL paused; | ||
|
||
/* Defines how many display frames must pass between each time the | ||
* display link fires. Default value is one, which means the display | ||
* link will fire for every display frame. Setting the interval to two | ||
* will cause the display link to fire every other display frame, and | ||
* so on. The behavior when using values less than one is undefined. */ | ||
|
||
@property(nonatomic) NSInteger frameInterval; | ||
|
||
@end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,159 @@ | ||
// | ||
// RCTDisplayLink.m | ||
// React | ||
// | ||
// Created by Stanislav Vishnevskiy on 6/8/15. | ||
// Copyright (c) 2015 Facebook. All rights reserved. | ||
// | ||
|
||
#import "DCDDisplayLink.h" | ||
#import <UIKit/UIKit.h> | ||
|
||
@interface DCDDisplayLink () | ||
|
||
@property(nonatomic) NSRunLoop *runloop; | ||
@property(nonatomic) NSString *mode; | ||
@property(nonatomic) id target; | ||
@property(nonatomic) SEL selector; | ||
@property(nonatomic) NSTimer *timer; | ||
@property(nonatomic) CADisplayLink *displayLink; | ||
|
||
// CADisplayLink is not thread safe. | ||
// Add a flag to avoid the crash of removing invalidated CADisplayLink from the run loop. | ||
@property(nonatomic) BOOL resourcesLoaded; | ||
|
||
@end | ||
|
||
@implementation DCDDisplayLink | ||
|
||
+ (DCDDisplayLink *)displayLinkWithTarget:(id)target selector:(SEL)sel { | ||
return [[self alloc] initWithTarget:target selector:sel]; | ||
} | ||
|
||
- (instancetype)initWithTarget:(id)target selector:(SEL)sel { | ||
if (self = [super init]) { | ||
_target = target; | ||
_selector = sel; | ||
_displayLink = [CADisplayLink displayLinkWithTarget:target selector:sel]; | ||
_resourcesLoaded = YES; | ||
|
||
[[NSNotificationCenter defaultCenter] addObserver:self | ||
selector:@selector(switchToTimer) | ||
name:UIApplicationDidEnterBackgroundNotification | ||
object:nil]; | ||
[[NSNotificationCenter defaultCenter] addObserver:self | ||
selector:@selector(switchToDisplayLink) | ||
name:UIApplicationWillEnterForegroundNotification | ||
object:nil]; | ||
} | ||
return self; | ||
} | ||
|
||
- (void)dealloc { | ||
[[NSNotificationCenter defaultCenter] removeObserver:self]; | ||
} | ||
|
||
- (void)switchToDisplayLink { | ||
if (_timer) { | ||
[_timer invalidate]; | ||
_timer = nil; | ||
[self setPaused:_paused]; | ||
if (_runloop) { | ||
[_displayLink addToRunLoop:_runloop forMode:_mode]; | ||
} | ||
} | ||
} | ||
|
||
- (void)switchToTimer { | ||
if (!_timer) { | ||
[self maybeResetTimer]; | ||
[self setPaused:_paused]; | ||
if (_runloop && _resourcesLoaded) { | ||
[_displayLink removeFromRunLoop:_runloop forMode:_mode]; | ||
[_runloop addTimer:_timer forMode:_mode]; | ||
} | ||
} | ||
} | ||
|
||
- (void)addToRunLoop:(NSRunLoop *)runloop forMode:(NSString *)mode { | ||
_runloop = runloop; | ||
_mode = mode; | ||
if (_timer) { | ||
[self maybeResetTimer]; | ||
[runloop addTimer:_timer forMode:mode]; | ||
} | ||
else { | ||
[_displayLink addToRunLoop:runloop forMode:mode]; | ||
} | ||
} | ||
|
||
- (void)removeFromRunLoop:(NSRunLoop *)runloop forMode:(NSString *)mode { | ||
_runloop = nil; | ||
_mode = nil; | ||
if (_timer) { | ||
[_timer invalidate]; | ||
} | ||
else { | ||
[_displayLink removeFromRunLoop:runloop forMode:mode]; | ||
} | ||
} | ||
|
||
- (void)invalidate { | ||
_resourcesLoaded = NO; | ||
if (_timer) { | ||
[_timer invalidate]; | ||
} | ||
else { | ||
[_displayLink invalidate]; | ||
} | ||
} | ||
|
||
- (void)setPaused:(BOOL)paused { | ||
_paused = paused; | ||
if (_timer) { | ||
if (paused) { | ||
[_timer invalidate]; | ||
} | ||
else { | ||
[self maybeResetTimer]; | ||
if (_runloop) { | ||
[_runloop addTimer:_timer forMode:_mode]; | ||
} | ||
} | ||
} | ||
else { | ||
_displayLink.paused = paused; | ||
} | ||
} | ||
|
||
- (CFTimeInterval)timestamp { | ||
if (_timer) { | ||
// TODO: Does React Native actually need this? | ||
return 0; | ||
} | ||
return _displayLink.timestamp; | ||
} | ||
|
||
- (CFTimeInterval)duration { | ||
if (_timer) { | ||
// TODO: Does React Native actually need this? | ||
return 0; | ||
} | ||
return _displayLink.duration; | ||
} | ||
|
||
- (void)maybeResetTimer { | ||
if (!_timer || ![_timer isValid]) { | ||
_timer = [NSTimer timerWithTimeInterval:1 target:self selector:@selector(timerLoop) userInfo:nil repeats:YES]; | ||
} | ||
} | ||
|
||
- (void)timerLoop { | ||
if (_target) { | ||
IMP imp = [_target methodForSelector:_selector]; | ||
void (*func)(id, SEL, DCDDisplayLink *) = (void *)imp; | ||
func(_target, _selector, self); | ||
} | ||
} | ||
|
||
@end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters