Why the sudden introduction and encapsulation of a Timer for GCDS? Mainly because recently in an interview, the interviewer asked me a question:

“If you were asked to create and encapsulate a Timer using GCD, what would you do?”

In this article, we will introduce how to use GCD for the use and encapsulation of Timer

Here is the GCDTimer code I have encapsulated, you can go to see. Out of the box.

OC version portal

Swift version portal

One: GCD timer introduction

GCD timers use a Dispatch source to listen to and process system kernel objects. This is somewhat similar to the producer-consumer pattern, which is executed by listening on objects and then notificating the corresponding Dispatch queue after the data is produced.

Two: why use GCD timer? Instead of using NSTimer?

NSTimer has the following problems compared to the system-provided NSTimer:

  1. NSTimer must ensure that in an active Runloop, this is enabled by default on the main thread and not on child threads. So you have to add it to a Runloop.
  2. NSTimer must be created and destroyed in the same thread.
  3. At the same time, because of the Runloop Mode problem, the ScrollView will cause NSTimer delay
  4. Causes circular references. Because NSTimer Target, in the case of Repeats, references Target. This will result in a release exception.

How to create a GCD timer

The GCD timer mainly uses the following functions:

-(void)GCDTimer{/** Creates a timer object. * Timer is a 'dispatch_source_t' type and needs to be defined globally. The local definition initialization life cycle is too short to perform callbacks. * First argument: Sourcer is defined as a timer. */ self.timer = dispatch_source_create(dispatch_source_timer, 0, 0) dispatch_get_global_queue(0, 0)); /** Sets the Timer * the first parameter is the dispatch source, which is the Timer you just created * when the second parameter is executed. Generally, DISPATCH_TIME_NOW will do for immediate execution. * If delayed execution is required, the 'dispatch_time_t' type can be created with dispatch_time. [dispatch_time(DISPATCH_TIME_NOW, 2 * NSEC_PER_SEC) = 2 seconds delay] * The third parameter is the interval. * The fourth is the error value. If I don't need an error, */ dispatch_source_set_timer(self.timer, dispatch_time(DISPATCH_TIME_NOW, 1 * NSEC_PER_SEC), 2 * NSEC_PER_SEC, 2 * NSEC_PER_SEC, 0 * NSEC_PER_SEC); __weak typeof(self) weakSelf = self; /** Set timer callback function * remember loop reference inside block * If timer in child thread, refresh UI, need to return to main thread. */ dispatch_source_set_event_handler(self.timer, ^{ [weakSelf doSomeThing]; }); /* Start or resume the timer. After the first creation, this method must be called to start the timer. **/ dispatch_resume(self.timer); /* Cancel timer */ dispatch_source_cancel(self.timer); /* Dispatch_suspend (self.timer); //dispatch_suspend(self.timer); }Copy the code

Four, knock the key!!

1. GCD timer does not have non-repeat option.

  • In addition, OC version is not, but in Swift version can be set.
  • So if our timer does not want to cycle, we must manually add a flag bit to determine.
__weak typeof(self) weakSelf = self;
dispatch_source_set_event_handler(self.timer, ^{

  if(!weakSelf.isRepeat){
      dispatch_source_cancel(weakSelf.timer);
  }   
  
});
Copy the code

2. dispatch_suspenddispatch_resumePair use.

  • Because it’s callingdispatch_suspendGCD records suspend by the number of suspends.
  • So it’s called multiple timesdispatch_suspend, must call an equal number ofdispatch_resume. The timer will not really resume until the number of suspensions reaches 0. If you call it 3 times in an operationdispatch_suspend, so you have to call it 3 times on recoverydispatch_resumeCan.)

3. It cannot be obtaineddispatch_suspendHang count and status of.

  • So when you calldispatch_suspendYou need to define a variable to record.

4. Precautions for canceling the timer

  • Set dispatch_source_t to nil when the number of dispatch_source_t suspends is greater than 0.
dispatch_suspend(self.timer);
dispatch_source_cancel(self.timer);
self.timer = nil; //Thread 1: EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0)

Copy the code

In the next article I will introduce my encapsulation ideas. If there are mistakes or bad, welcome to point out ~

If my article can help you, please click like attention, thank you ~

Finally, I wish you a happy life ~

OC version portal

Swift version portal