Add block handling functions to NSTimer

This commit is contained in:
Gregory John Casamento 2019-10-26 17:03:38 -04:00
parent 3d6cd160b2
commit 873e4edc47
4 changed files with 128 additions and 50 deletions

View file

@ -51,7 +51,7 @@ enum {
}; };
typedef NSInteger NSQualityOfService; typedef NSInteger NSQualityOfService;
@class NSString; @class NSString, NSTimer;
DEFINE_BLOCK_TYPE(NSBackgroundActivityCompletionHandler, void, NSBackgroundActivityResult); DEFINE_BLOCK_TYPE(NSBackgroundActivityCompletionHandler, void, NSBackgroundActivityResult);
DEFINE_BLOCK_TYPE(GSScheduledBlock, void, NSBackgroundActivityCompletionHandler); DEFINE_BLOCK_TYPE(GSScheduledBlock, void, NSBackgroundActivityCompletionHandler);
@ -64,6 +64,7 @@ DEFINE_BLOCK_TYPE(GSScheduledBlock, void, NSBackgroundActivityCompletionHandler)
NSTimeInterval _tolerance; NSTimeInterval _tolerance;
BOOL _repeats; BOOL _repeats;
BOOL _shouldDefer; BOOL _shouldDefer;
NSTimer *_timer;
} }
- (instancetype) initWithIdentifier: (NSString *)identifier; - (instancetype) initWithIdentifier: (NSString *)identifier;
@ -81,7 +82,7 @@ DEFINE_BLOCK_TYPE(GSScheduledBlock, void, NSBackgroundActivityCompletionHandler)
- (void) setInterval: (NSTimeInterval)interval; - (void) setInterval: (NSTimeInterval)interval;
- (NSTimeInterval) tolerance; - (NSTimeInterval) tolerance;
- (void) setTolerance: (NSTimeInterval)interval; - (void) setTolerance: (NSTimeInterval)tolerance;
- (BOOL) shouldDefer; - (BOOL) shouldDefer;
- (void) setShouldDefer: (BOOL)flag; - (void) setShouldDefer: (BOOL)flag;

View file

@ -28,6 +28,9 @@
#import <Foundation/NSDate.h> #import <Foundation/NSDate.h>
@class NSTimer;
DEFINE_BLOCK_TYPE(GSTimerBlock, void, NSTimer*);
#if defined(__cplusplus) #if defined(__cplusplus)
extern "C" { extern "C" {
#endif #endif
@ -43,13 +46,14 @@ extern "C" {
{ {
#if GS_EXPOSE(NSTimer) #if GS_EXPOSE(NSTimer)
@public @public
NSDate *_date; /* Must be first - for NSRunLoop optimisation */ NSDate *_date; /* Must be 1st - for NSRunLoop optimisation */
BOOL _invalidated; /* Must be 2nd - for NSRunLoop optimisation */ BOOL _invalidated; /* Must be 2nd - for NSRunLoop optimisation */
BOOL _repeats; BOOL _repeats;
NSTimeInterval _interval; NSTimeInterval _interval;
id _target; id _target;
SEL _selector; SEL _selector;
id _info; id _info;
GSTimerBlock _block;
#endif #endif
#if GS_NONFRAGILE #if GS_NONFRAGILE
#else #else
@ -67,15 +71,21 @@ extern "C" {
+ (NSTimer*) scheduledTimerWithTimeInterval: (NSTimeInterval)ti + (NSTimer*) scheduledTimerWithTimeInterval: (NSTimeInterval)ti
invocation: (NSInvocation*)invocation invocation: (NSInvocation*)invocation
repeats: (BOOL)f; repeats: (BOOL)f;
+ (NSTimer*) scheduledTimerWithTimeInterval: (NSTimeInterval)ti + (NSTimer*) scheduledTimerWithTimeInterval: (NSTimeInterval)ti
target: (id)object target: (id)object
selector: (SEL)selector selector: (SEL)selector
userInfo: (id)info userInfo: (id)info
repeats: (BOOL)f; repeats: (BOOL)f;
+ (NSTimer *) scheduledTimerWithTimeInterval: (NSTimeInterval)ti
repeats: (BOOL)f
block: (GSTimerBlock)block;
+ (NSTimer*) timerWithTimeInterval: (NSTimeInterval)ti + (NSTimer*) timerWithTimeInterval: (NSTimeInterval)ti
invocation: (NSInvocation*)invocation invocation: (NSInvocation*)invocation
repeats: (BOOL)f; repeats: (BOOL)f;
+ (NSTimer*) timerWithTimeInterval: (NSTimeInterval)ti + (NSTimer*) timerWithTimeInterval: (NSTimeInterval)ti
target: (id)object target: (id)object
selector: (SEL)selector selector: (SEL)selector
@ -102,6 +112,13 @@ extern "C" {
- (void) setFireDate: (NSDate*)fireDate; - (void) setFireDate: (NSDate*)fireDate;
#endif #endif
#if OS_API_VERSION(MAC_OS_X_VERSION_10_12, GS_API_LATEST)
- (instancetype)initWithFireDate:(NSDate *)date
interval:(NSTimeInterval)interval
repeats:(BOOL)repeats
block:(GSTimerBlock)block;
#endif
@end @end
#if defined(__cplusplus) #if defined(__cplusplus)

View file

@ -37,6 +37,7 @@
_interval = 0; _interval = 0;
_tolerance = 0; _tolerance = 0;
_shouldDefer = NO; _shouldDefer = NO;
_timer = nil;
} }
return self; return self;
} }
@ -103,6 +104,30 @@
- (void) scheduleWithBlock: (GSScheduledBlock)block - (void) scheduleWithBlock: (GSScheduledBlock)block
{ {
NSProcessInfo *pinfo = [NSProcessInfo processInfo];
id token = nil;
NSActivityOptions opts = 0;
switch(qualityOfService)
{
case NSQualityOfServiceUserInteractive:
opts = NSActivityUserInitiated | NSActivityIdleDisplaySleepDisabled;
break;
case NSQualityOfServiceUserInitiated:
opts = NSActivityUserInitiated;
break;
case NSQualityOfServiceUtility:
opts = NSActivityUserInitiated | NSActivityIdleDisplaySleepDisabled;
break;
case NSQualityOfServiceBackground:
opts = NSActivityBackground;
break;
case NSQualityOfServiceDefault:
opts = NSActivityLatencyCritical;
break;
}
token = [pinfo beginActivityWithOptions:
} }
- (void) invalidate - (void) invalidate

View file

@ -145,6 +145,20 @@ static Class NSDate_class;
return self; return self;
} }
- (instancetype)initWithFireDate:(NSDate *)date
interval:(NSTimeInterval)interval
repeats:(BOOL)repeats
block:(GSTimerBlock)block
{
return [self initWithFireDate: date
interval: interval
target: nil
selector: NULL
userInfo: nil
repeats: repeats];
ASSIGN(_block, block);
}
/** /**
* Create a timer which will fire after ti seconds and, if f is YES, * Create a timer which will fire after ti seconds and, if f is YES,
* every ti seconds thereafter. On firing, invocation will be performed.<br /> * every ti seconds thereafter. On firing, invocation will be performed.<br />
@ -229,6 +243,19 @@ static Class NSDate_class;
return t; return t;
} }
+ (NSTimer *) scheduledTimerWithTimeInterval: (NSTimeInterval)ti
repeats: (BOOL)f
block: (GSTimerBlock)block
{
id t = [[self alloc] initWithFireDate: nil
interval: ti
repeats: f
block: block];
[[NSRunLoop currentRunLoop] addTimer: t forMode: NSDefaultRunLoopMode];
RELEASE(t);
return t;
}
- (void) dealloc - (void) dealloc
{ {
if (_invalidated == NO) if (_invalidated == NO)
@ -251,48 +278,56 @@ static Class NSDate_class;
*/ */
if (NO == _invalidated) if (NO == _invalidated)
{ {
id target; if(_block != nil)
{
/* We retain the target so it won't be deallocated while we are using it CALL_BLOCK(_block, self);
* (if this timer gets invalidated while we are firing). }
*/
target = RETAIN(_target);
if (_selector == 0)
{
NS_DURING
{
[(NSInvocation*)target invoke];
}
NS_HANDLER
{
NSLog(@"*** NSTimer ignoring exception '%@' (reason '%@') "
@"raised during posting of timer with target %s(%s) "
@"and selector '%@'",
[localException name], [localException reason],
GSClassNameFromObject(target),
GSObjCIsInstance(target) ? "instance" : "class",
NSStringFromSelector([target selector]));
}
NS_ENDHANDLER
}
else else
{ {
NS_DURING id target;
{
[target performSelector: _selector withObject: self]; /* We retain the target so it won't be deallocated while we are using it
} * (if this timer gets invalidated while we are firing).
NS_HANDLER */
{ target = RETAIN(_target);
NSLog(@"*** NSTimer ignoring exception '%@' (reason '%@') "
@"raised during posting of timer with target %p and " if (_selector == 0)
@"selector '%@'", {
[localException name], [localException reason], target, NS_DURING
NSStringFromSelector(_selector)); {
} [(NSInvocation*)target invoke];
NS_ENDHANDLER }
} NS_HANDLER
RELEASE(target); {
NSLog(@"*** NSTimer ignoring exception '%@' (reason '%@') "
@"raised during posting of timer with target %s(%s) "
@"and selector '%@'",
[localException name], [localException reason],
GSClassNameFromObject(target),
GSObjCIsInstance(target) ? "instance" : "class",
NSStringFromSelector([target selector]));
}
NS_ENDHANDLER
}
else
{
NS_DURING
{
[target performSelector: _selector withObject: self];
}
NS_HANDLER
{
NSLog(@"*** NSTimer ignoring exception '%@' (reason '%@') "
@"raised during posting of timer with target %p and "
@"selector '%@'",
[localException name], [localException reason], target,
NSStringFromSelector(_selector));
}
NS_ENDHANDLER
}
RELEASE(target);
}
if (_repeats == NO) if (_repeats == NO)
{ {
[self invalidate]; [self invalidate];