早期我们使用延时执行的方法都是用NSObject 类提供的,performSelector:系列的方法,具体有哪些我们看一下
我们一般让某个对象延时执行某个方法都会调用包含 afterDelay这个参数的方法,此参数即代表延时多长时间执行 ,但是这一系列的方法的参数都只接受继承自NSObject类得对象,也就是说如果我们要向其中传入基本的数据类型,那就必须涉及到数据类型转换,这显然会增加开销,而且这一系列的方法最多也就能传如一个参数,如果我们要传多个参数怎么办呢 ,如果想继续使用这个方法,那我们就必须把多个参数写入数组或字典中去,然后把数组或字典对象传给这个方法,那么着就又会增加我们插入数组或字典,解析数组或字典的代码 ,数据量达到一定情况的话,这个开销是可想而知的,而且我们还要知道数组和字典中得每个对象都代表什么,很麻烦;
不过我们可以用块来解决这一问题 ,GCD 为我们提供了一个演示执行的块函数,其具体定义如下:
void dispatch_after ( dispatch_time_t when, dispatch_queue_t queue, dispatch_block_t block );
我们在调用此方法的时候,系统也考虑的很周到,当我们写入dispatch_after时,这个完整的函数就会呈现出来,我们看一下
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ });
调用很方便,如果我们想把里面的内容放到主线程中去运行的话,也很方便,例如:
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ dispatch_async(dispatch_get_main_queue(), ^{ [son study]; }); });
还记得当时有一个问题,就是想给UIButton的点击事件加点料,让系统中的所有的按钮都禁止快速点击或者连击,当时问了看了好多博客,都没有好的解决方案,前篇一律的讨论或者建议,都是使用performSelector:afterDelay这种方法,但是这样的话,我还要实现另一个方法 。后来是这么解决的呢 ,这里再次引用我之前写的内容,重写父类函数,然后使用GCD的dispatch_after 方法解决;
具体实现如下:
// // CommonButton.h // CommonButton // // Created by pk on 14/12/24. // Copyright (c) 2014年 pk. All rights reserved. // #import <UIKit/UIKit.h> @interface CommonButton : UIButton @end
// // CommonButton.m // CommonButton // // Created by pk on 14/12/24. // Copyright (c) 2014年 pk. All rights reserved. // #import "CommonButton.h" @implementation CommonButton /* // Only override drawRect: if you perform custom drawing. // An empty implementation adversely affects performance during animation. - (void)drawRect:(CGRect)rect { // Drawing code } */ - (void)sendAction:(SEL)action to:(id)target forEvent:(UIEvent *)event { [super sendAction:action to:target forEvent:event]; self.enabled = NO; dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ self.enabled = YES; }); } @end
这样的实现,很清楚,结构简明,使用简单,想使用此方法,只要将改一下类得继承就行;
总结:performSelector 系列方法所能处理的选择器太过于局限性了 ,选择器的返回值类型和参数的个数都会受到限制;
而dispatch_after就没有这些问题,另外,如果想把任务放在另一个线程上执行,最好不要用performSelector系列方法,而应该把任务封装到块里,然后调用GCD的相关方法来实现就行