SoFunction
Updated on 2025-04-11

Implementation principle of the simple and easy-to-use GCD timer for iOS

Preface

I haven't updated the article for a long time. When the Nuggets posted the article for the first time, I still set up a flag for myself to update at least one article a week. The quality of the article may not be very satisfactory. I hope to improve my writing style by writing articles and record the solutions to problems encountered in my studies.

In the process of learning iOS, everyone is familiar with timers. In daily development, they will always encounter functions that require timers. Common timers include NSTimer, GCD, and CADisplayLink. There are also many tutorials online to introduce the differences between the three. Today we mainly talk about the use and packaging of GCD.

The difference between the three

advantage shortcoming
NSTimer Easy to use The impact of Runloop will cause inaccurate timing
CADisplayLink High accuracy When the CPU is loaded, the trigger event will be affected, and the trigger event is greater than the trigger interval, which will cause frame drop.
GCD More accurate There are many codes, basically no other influence

Summary: NSTimer and CADisplayLink are easily affected, while GCD has a lot of code, but it is very controllable.

GCD

/** Get a global thread to run the timer*/
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
/** Create a timer*/
dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
/** Set the timer, here is executed every 10 milliseconds*/
dispatch_source_set_timer(timer, dispatch_walltime(nil, 0), 10*NSEC_PER_MSEC, 0);
/** Set the timer's operation event*/
dispatch_source_set_event_handler(timer, ^{
 //do you want....
});

Turn on and continue the paused timer

dispatch_resume(timer);

Pause timer

/** When suspending, pay attention to the fact that multiple pauses will lead to thread locking, that is, how many pauses will be done.
 * The corresponding number of continuous operations, namely dispatch_suspend and dispatch_resume
 * Only when the timer continues to work is present in pairs.
 */
dispatch_suspend(timer);

End timer

dispatch_source_cancel(timer);

Conceive packaging

Before writing code, you should think about the functional modules, solutions to problems you will encounter, and code logic, and then start writing code manually, which will result twice the result with half the effort.

  • It must include start, pause, continue, stop, and reset functions
  • During the time calculation process, accuracy will be lost due to floating point calculations. The calculation process should use NSDecimal.
  • Time conversion takes into account accuracy and convenience, and adopts the system's time conversion method, and the time zone is set to GMT.
  • Since the APP enters the background, if the switch of the background task is not turned on, the timer will stop, and the APP will continue again when entering the APP again. Therefore, the time stamp of the APP entering the background and the foreground is recorded by monitoring the app status, and compared with the deadline, whether to continue to count or end the timing and callback.
  • If the result returned by the timer is a string, it still needs to be processed. Therefore, a time class is used to return the result, and custom operations can be performed.
  • The return and end notification of the countdown result are in closure form

Part of the code

/** app enters the background*/
- (void)appDidEnterBackground{
  [self suspend];
  NSDate *date = [[NSDate alloc] init];
  NSDateFormatter *format = [[NSDateFormatter alloc] init];
   = @"yyyy-MM-dd HH:mm:ss:SSS";
   = [date timeIntervalSince1970];
}

/** app enters the front desk*/
- (void)appDidEnterForeground{
  NSDate *date = [[NSDate alloc] init];
  NSDateFormatter *format = [[NSDateFormatter alloc] init];
   = @"yyyy-MM-dd HH:mm:ss";
   = [date timeIntervalSince1970];
  [self reCalculateMinder];
}

/** Unabsorbed accuracy calculation results*/

- (NSDecimalNumber *)value: (NSTimeInterval)value 
        byOpration: (OMDecimalOprationType)byOpration    
         percision: (NSInteger)percision 
        withValue: (NSTimeInterval)withValue{

  NSDecimalNumber *number = [self numberValueWithString: value];
  NSDecimalNumber *withNumber = [self numberValueWithString: withValue]; 
  NSDecimalNumberHandler *handler = [NSDecimalNumberHandler decimalNumberHandlerWithRoundingMode: NSRoundPlain scale: percision raiseOnExactness: NO raiseOnOverflow: NO raiseOnUnderflow: NO raiseOnDivideByZero: YES];

switch (byOpration) {
  case OMDecimalOprationTypeAdd:
   return [number decimalNumberByAdding: withNumber withBehavior:handler];
   break;
  case OMDecimalOprationTypeSubtract:
   return [number decimalNumberBySubtracting: withNumber withBehavior: handler];
   break;
  case OMDecimalOprationTypeDivide:
   return [number decimalNumberByDividingBy: withNumber withBehavior: handler];
   break;
 case OMDecimalOprationTypeMultiple:
   return [number decimalNumberByMultiplyingBy: withNumber withBehavior: handler];
   break;
 default:
   break;
   return nil;
}

@property (nonatomic, strong) OMTimer *timer;
 = [[OMTimer alloc] init];
 = 30;
 = 100;
 = NO;
 = ^(OMTime *progress) {
   NSLog(@"%@:%@:%@:%@", , , , ;
}; = ^{
  NSLog(@"complete done!");
};

Swift version

I have fallen in love with OC recently. If you need a Swift version, you can leave a message or private me. You can write a Swift version:stuck_out_tongue_winking_eye:.

Conclusion

Simple to use, just drag the sum into your project, satisfying the scenario of large numbers, counting down or increasing the timing, all codes are already on Github</oymuzi/OMKit/

The above is all the content of this article. I hope it will be helpful to everyone's study and I hope everyone will support me more.