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:
- 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.
- NSTimer must be created and destroyed in the same thread.
- At the same time, because of the Runloop Mode problem, the ScrollView will cause NSTimer delay
- 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_suspend
和 dispatch_resume
Pair use.
- Because it’s calling
dispatch_suspend
GCD records suspend by the number of suspends. - So it’s called multiple times
dispatch_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_resume
Can.)
3. It cannot be obtaineddispatch_suspend
Hang count and status of.
- So when you call
dispatch_suspend
You 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