废话不多说,直接从GCD所提供的函数说起。
dispatch_once
相信大家对单例模式可谓是司空见惯了吧,常见的实现方式是:在某个类中编写名为sharedInstance的类方法,该方法只会返回该类共用的单例实例,而不会在每次调用时都创建新的实例。假设有个类为FTHImage,一般会这样写:
#import "FTHImage.h"
@implementation FTHImage
+ (FTHImage *)sharedImage {
static FTHImage *shareImage = nil;
@synchronized (self) {
if (!shareImage) {
shareImage = [[self alloc] init];
}
}
return shareImage;
}
@end
但是这种单例实现并不是线程安全的,单例实例化代码会执行多次,而不是一次。还好,GCD引入一项特性,即dispatch_once函数。
void dispatch_once(dispatch_once_t *predicate, dispatch_block_t block);```
- 此函数有个类型为dispatch_once_t 的参数(其实可以将它看作是一个“标记”)以及一个块参数。
- 使用dispatch_once简化了代码而且彻底保证线程安全,开发者无需担心加锁以及同步的问题,因为GCD都会帮你在底层处理搞定。
- 另外每次调用都必须使用完全相同的标记,所以标记应该声明为static,由此可以保证编译器在每次执行单例方法时都会复用这个变量,从而不会创建新的变量。
######再次说明,编写只需执行一次的线程安全代码,通过GCD提供的dispatch_once函数就可以实现。并且在性能方面,比采用@synchronized的方式来得更高效。
用此函数改写上面的代码:
import "FTHImage.h"
@implementation FTHImage
- (FTHImage *)sharedImage {
static FTHImage *shareImage = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
shareImage = [[self alloc] init];
});
return shareImage;
}
@end
####dispatch_async
当你需要在<b>后台执行</b>一个基于网络或 CPU 紧张的任务时就使用 dispatch_async ,这样就不会阻塞当前线程。dispatch_async 添加一个 Block 到队列就立即返回了。任务会在之后由 GCD 决定执行。使用如下:
dispatch_async(queue, ^{
//长时间处理,例如下载网络图片,获取网络数据,数据库访问等
dispatch_async( dispatch_get_main_queue(), ^{
//只在主线程可以执行的处理
//例如用户界面更新
});
});
来个简单的例子,好吧,还是以图片下载后显示为例。
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(queue, ^{
// 异步下载图片
NSURL *url = [NSURL URLWithString:@"http://xx.jpg"];
NSData *data = [NSData dataWithContentsOfURL:url]; //
UIImage *image = [UIImage imageWithData:data];
// 回到主线程显示图片
dispatch_async(dispatch_get_main_queue(), ^{
self.imageView.image = image;
});
});
####dispatch_after
dispatch_after用来延后将操作放入队列。
dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, (int64_t) (5.0 * NSEC_PER_SEC));
dispatch_after(time, dispatch_get_main_queue(), ^(void) {
[self doSomething];
});
dispatch_after其实就是一个延迟版的 dispatch_async。
其它待续。
网友评论