Delayed execution is still a common requirement in Objective-C, and there are usually several ways to choose from:
performSelector:
Want to delay calling a method:
[self performSelector:@selector(delay) withObject:nil afterDelay:3.0];
Methods to cancel delay:
[NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(delay) object:nil];
Here you need to note that the parameters need to be consistent, otherwise the cancellation will fail.
NSTimer
Want to delay calling a method:
= [NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:@selector(delay) userInfo:nil repeats:NO];
Methods to cancel delay:
[ invalidate]; GCD dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ // ... });
dispatch_after is a common method, but there is no relevant API for canceling execution in Objective-C. We can only implement this cancellation logic ourselves:
typedef void (^Task)(BOOL cancel); Task delay(NSTimeInterval time,void (^task)()) { __block void (^closure)() = task; __block Task result; Task delayedClosure = ^(BOOL cancel){ if (closure) { void (^internalClosure)() = closure; if (!cancel) { dispatch_async(dispatch_get_main_queue(), internalClosure); } } closure = nil; result = nil; }; result = delayedClosure; dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(time * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ if (delayedClosure) { delayedClosure(NO); } }); return result; } If used, this is possible: delay(60, ^{ // ... });
If you want a delay, you can declare it as a member variable and assign a value:
@property (copy, nonatomic) Task task; = delay(60, ^{ // ... });
Finally, cancel where needed:
(YES);
The core idea of this writing method is to control whether the method in the dispatch_after callback block needs to be executed based on the incoming Bool value. It seems to have been cancelled, but in fact it is still put into RunLoop by GCD to occupy the main thread resources.
dispatch_source
We can also use the timer in dispatch_source to implement delay/cancel operation:
@property (strong, nonatomic) dispatch_source_t timer; // Queuedispatch_queue_t queue = dispatch_get_main_queue(); // Create dispatch_sourcedispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue); // Declare member variables = timer; // It will trigger after setting two secondsdispatch_time_t startTime = dispatch_time(DISPATCH_TIME_NOW, 3.0 * NSEC_PER_SEC); // Set the next trigger event to DISPATCH_TIME_FOREVERdispatch_time_t nextTime = DISPATCH_TIME_FOREVER; // Set accuracydispatch_time_t leeway = 0.1 * NSEC_PER_SEC; //Configuration timedispatch_source_set_timer(timer, startTime, nextTime, leeway); // Callbackdispatch_source_set_event_handler(timer, ^{ // ... }); // activationdispatch_resume(timer);
If you need to cancel:
dispatch_source_cancel();