diff --git a/Headers/Foundation/NSBackgroundActivityScheduler.h b/Headers/Foundation/NSBackgroundActivityScheduler.h index 1f93db348..35d9e5212 100644 --- a/Headers/Foundation/NSBackgroundActivityScheduler.h +++ b/Headers/Foundation/NSBackgroundActivityScheduler.h @@ -51,7 +51,7 @@ enum { }; typedef NSInteger NSQualityOfService; -@class NSString; +@class NSString, NSTimer; DEFINE_BLOCK_TYPE(NSBackgroundActivityCompletionHandler, void, NSBackgroundActivityResult); DEFINE_BLOCK_TYPE(GSScheduledBlock, void, NSBackgroundActivityCompletionHandler); @@ -64,6 +64,7 @@ DEFINE_BLOCK_TYPE(GSScheduledBlock, void, NSBackgroundActivityCompletionHandler) NSTimeInterval _tolerance; BOOL _repeats; BOOL _shouldDefer; + NSTimer *_timer; } - (instancetype) initWithIdentifier: (NSString *)identifier; @@ -81,7 +82,7 @@ DEFINE_BLOCK_TYPE(GSScheduledBlock, void, NSBackgroundActivityCompletionHandler) - (void) setInterval: (NSTimeInterval)interval; - (NSTimeInterval) tolerance; -- (void) setTolerance: (NSTimeInterval)interval; +- (void) setTolerance: (NSTimeInterval)tolerance; - (BOOL) shouldDefer; - (void) setShouldDefer: (BOOL)flag; diff --git a/Headers/Foundation/NSTimer.h b/Headers/Foundation/NSTimer.h index 1ee7f6815..b2b2ceffa 100644 --- a/Headers/Foundation/NSTimer.h +++ b/Headers/Foundation/NSTimer.h @@ -28,6 +28,9 @@ #import +@class NSTimer; +DEFINE_BLOCK_TYPE(GSTimerBlock, void, NSTimer*); + #if defined(__cplusplus) extern "C" { #endif @@ -43,13 +46,14 @@ extern "C" { { #if GS_EXPOSE(NSTimer) @public - NSDate *_date; /* Must be first - for NSRunLoop optimisation */ - BOOL _invalidated; /* Must be 2nd - for NSRunLoop optimisation */ - BOOL _repeats; + NSDate *_date; /* Must be 1st - for NSRunLoop optimisation */ + BOOL _invalidated; /* Must be 2nd - for NSRunLoop optimisation */ + BOOL _repeats; NSTimeInterval _interval; - id _target; - SEL _selector; - id _info; + id _target; + SEL _selector; + id _info; + GSTimerBlock _block; #endif #if GS_NONFRAGILE #else @@ -67,15 +71,21 @@ extern "C" { + (NSTimer*) scheduledTimerWithTimeInterval: (NSTimeInterval)ti invocation: (NSInvocation*)invocation repeats: (BOOL)f; + + (NSTimer*) scheduledTimerWithTimeInterval: (NSTimeInterval)ti target: (id)object selector: (SEL)selector userInfo: (id)info repeats: (BOOL)f; - + ++ (NSTimer *) scheduledTimerWithTimeInterval: (NSTimeInterval)ti + repeats: (BOOL)f + block: (GSTimerBlock)block; + + (NSTimer*) timerWithTimeInterval: (NSTimeInterval)ti invocation: (NSInvocation*)invocation repeats: (BOOL)f; + + (NSTimer*) timerWithTimeInterval: (NSTimeInterval)ti target: (id)object selector: (SEL)selector @@ -102,6 +112,13 @@ extern "C" { - (void) setFireDate: (NSDate*)fireDate; #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 #if defined(__cplusplus) diff --git a/Source/NSBackgroundActivityScheduler.m b/Source/NSBackgroundActivityScheduler.m index edf0afd7e..fa9f4fd9d 100644 --- a/Source/NSBackgroundActivityScheduler.m +++ b/Source/NSBackgroundActivityScheduler.m @@ -37,6 +37,7 @@ _interval = 0; _tolerance = 0; _shouldDefer = NO; + _timer = nil; } return self; } @@ -103,6 +104,30 @@ - (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 diff --git a/Source/NSTimer.m b/Source/NSTimer.m index 4173d6cd1..ca0823fe8 100644 --- a/Source/NSTimer.m +++ b/Source/NSTimer.m @@ -145,6 +145,20 @@ static Class NSDate_class; 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, * every ti seconds thereafter. On firing, invocation will be performed.
@@ -229,6 +243,19 @@ static Class NSDate_class; 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 { if (_invalidated == NO) @@ -251,48 +278,56 @@ static Class NSDate_class; */ if (NO == _invalidated) { - id target; - - /* We retain the target so it won't be deallocated while we are using it - * (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 - } + if(_block != nil) + { + CALL_BLOCK(_block, self); + } 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); + { + id target; + + /* We retain the target so it won't be deallocated while we are using it + * (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 + { + 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) { [self invalidate];