RACQueueScheduler.m 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106
  1. //
  2. // RACQueueScheduler.m
  3. // ReactiveObjC
  4. //
  5. // Created by Josh Abernathy on 11/30/12.
  6. // Copyright (c) 2012 GitHub, Inc. All rights reserved.
  7. //
  8. #import "RACQueueScheduler.h"
  9. #import "RACDisposable.h"
  10. #import "RACQueueScheduler+Subclass.h"
  11. #import "RACScheduler+Private.h"
  12. @implementation RACQueueScheduler
  13. #pragma mark Lifecycle
  14. - (instancetype)initWithName:(NSString *)name queue:(dispatch_queue_t)queue {
  15. NSCParameterAssert(queue != NULL);
  16. self = [super initWithName:name];
  17. _queue = queue;
  18. #if !OS_OBJECT_USE_OBJC
  19. dispatch_retain(_queue);
  20. #endif
  21. return self;
  22. }
  23. #if !OS_OBJECT_USE_OBJC
  24. - (void)dealloc {
  25. if (_queue != NULL) {
  26. dispatch_release(_queue);
  27. _queue = NULL;
  28. }
  29. }
  30. #endif
  31. #pragma mark Date Conversions
  32. + (dispatch_time_t)wallTimeWithDate:(NSDate *)date {
  33. NSCParameterAssert(date != nil);
  34. double seconds = 0;
  35. double frac = modf(date.timeIntervalSince1970, &seconds);
  36. struct timespec walltime = {
  37. .tv_sec = (time_t)fmin(fmax(seconds, LONG_MIN), LONG_MAX),
  38. .tv_nsec = (long)fmin(fmax(frac * NSEC_PER_SEC, LONG_MIN), LONG_MAX)
  39. };
  40. return dispatch_walltime(&walltime, 0);
  41. }
  42. #pragma mark RACScheduler
  43. - (RACDisposable *)schedule:(void (^)(void))block {
  44. NSCParameterAssert(block != NULL);
  45. RACDisposable *disposable = [[RACDisposable alloc] init];
  46. dispatch_async(self.queue, ^{
  47. if (disposable.disposed) return;
  48. [self performAsCurrentScheduler:block];
  49. });
  50. return disposable;
  51. }
  52. - (RACDisposable *)after:(NSDate *)date schedule:(void (^)(void))block {
  53. NSCParameterAssert(date != nil);
  54. NSCParameterAssert(block != NULL);
  55. RACDisposable *disposable = [[RACDisposable alloc] init];
  56. dispatch_after([self.class wallTimeWithDate:date], self.queue, ^{
  57. if (disposable.disposed) return;
  58. [self performAsCurrentScheduler:block];
  59. });
  60. return disposable;
  61. }
  62. - (RACDisposable *)after:(NSDate *)date repeatingEvery:(NSTimeInterval)interval withLeeway:(NSTimeInterval)leeway schedule:(void (^)(void))block {
  63. NSCParameterAssert(date != nil);
  64. NSCParameterAssert(interval > 0.0 && interval < INT64_MAX / NSEC_PER_SEC);
  65. NSCParameterAssert(leeway >= 0.0 && leeway < INT64_MAX / NSEC_PER_SEC);
  66. NSCParameterAssert(block != NULL);
  67. uint64_t intervalInNanoSecs = (uint64_t)(interval * NSEC_PER_SEC);
  68. uint64_t leewayInNanoSecs = (uint64_t)(leeway * NSEC_PER_SEC);
  69. dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, self.queue);
  70. dispatch_source_set_timer(timer, [self.class wallTimeWithDate:date], intervalInNanoSecs, leewayInNanoSecs);
  71. dispatch_source_set_event_handler(timer, block);
  72. dispatch_resume(timer);
  73. return [RACDisposable disposableWithBlock:^{
  74. dispatch_source_cancel(timer);
  75. }];
  76. }
  77. @end