YYTimer.m 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
  1. //
  2. // YYTimer.m
  3. // YYKit <https://github.com/ibireme/YYKit>
  4. //
  5. // Created by ibireme on 15/2/7.
  6. // Copyright (c) 2015 ibireme.
  7. //
  8. // This source code is licensed under the MIT-style license found in the
  9. // LICENSE file in the root directory of this source tree.
  10. //
  11. #import "YYTimer.h"
  12. #import <pthread.h>
  13. #define LOCK(...) dispatch_semaphore_wait(_lock, DISPATCH_TIME_FOREVER); \
  14. __VA_ARGS__; \
  15. dispatch_semaphore_signal(_lock);
  16. @implementation YYTimer {
  17. BOOL _valid;
  18. NSTimeInterval _timeInterval;
  19. BOOL _repeats;
  20. __weak id _target;
  21. SEL _selector;
  22. dispatch_source_t _source;
  23. dispatch_semaphore_t _lock;
  24. }
  25. + (YYTimer *)timerWithTimeInterval:(NSTimeInterval)interval
  26. target:(id)target
  27. selector:(SEL)selector
  28. repeats:(BOOL)repeats {
  29. return [[self alloc] initWithFireTime:interval interval:interval target:target selector:selector repeats:repeats];
  30. }
  31. + (YYTimer *)timerWithFireTime:(NSTimeInterval)start
  32. timeInterval:(NSTimeInterval)interval
  33. target:(id)target
  34. selector:(SEL)selector
  35. repeats:(BOOL)repeats {
  36. return [[self alloc] initWithFireTime:start interval:interval target:target selector:selector repeats:repeats];
  37. }
  38. - (instancetype)init {
  39. @throw [NSException exceptionWithName:@"YYTimer init error" reason:@"Use the designated initializer to init." userInfo:nil];
  40. return [self initWithFireTime:0 interval:0 target:self selector:@selector(invalidate) repeats:NO];
  41. }
  42. - (instancetype)initWithFireTime:(NSTimeInterval)start
  43. interval:(NSTimeInterval)interval
  44. target:(id)target
  45. selector:(SEL)selector
  46. repeats:(BOOL)repeats {
  47. self = [super init];
  48. _repeats = repeats;
  49. _timeInterval = interval;
  50. _valid = YES;
  51. _target = target;
  52. _selector = selector;
  53. __weak typeof(self) _self = self;
  54. _lock = dispatch_semaphore_create(1);
  55. _source = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_main_queue());
  56. dispatch_source_set_timer(_source, dispatch_time(DISPATCH_TIME_NOW, (start * NSEC_PER_SEC)), (interval * NSEC_PER_SEC), 0);
  57. dispatch_source_set_event_handler(_source, ^{[_self fire];});
  58. dispatch_resume(_source);
  59. return self;
  60. }
  61. - (void)invalidate {
  62. dispatch_semaphore_wait(_lock, DISPATCH_TIME_FOREVER);
  63. if (_valid) {
  64. dispatch_source_cancel(_source);
  65. _source = NULL;
  66. _target = nil;
  67. _valid = NO;
  68. }
  69. dispatch_semaphore_signal(_lock);
  70. }
  71. - (void)fire {
  72. #pragma clang diagnostic push
  73. #pragma clang diagnostic ignored "-Warc-performSelector-leaks"
  74. dispatch_semaphore_wait(_lock, DISPATCH_TIME_FOREVER);
  75. id target = _target;
  76. if (!_repeats || !target) {
  77. dispatch_semaphore_signal(_lock);
  78. [self invalidate];
  79. } else {
  80. dispatch_semaphore_signal(_lock);
  81. [target performSelector:_selector withObject:self];
  82. }
  83. #pragma clang diagnostic pop
  84. }
  85. - (BOOL)repeats {
  86. LOCK(BOOL repeat = _repeats); return repeat;
  87. }
  88. - (NSTimeInterval)timeInterval {
  89. LOCK(NSTimeInterval t = _timeInterval) return t;
  90. }
  91. - (BOOL)isValid {
  92. LOCK(BOOL valid = _valid) return valid;
  93. }
  94. - (void)dealloc {
  95. [self invalidate];
  96. }
  97. @end