您的位置:首页 > 移动开发 > IOS开发

iOS gcd

2016-03-04 09:00 344 查看
转至: http://www.cnblogs.com/zzltjnh/p/zzl_gcd.html
一、什么是GCD?

  Grand Central Dispatch (GCD)是Apple开发的一个多核编程的解决方法。该方法在Mac OS X 10.6雪豹中首次推出,并随后被引入到了iOS4.0中。GCD是一个替代诸如NSThread, NSOperationQueue, NSInvocationOperation等技术的很高效和强大的技术。

二、什么时候使用多线程

  我个人理解,在实际开发中我们常常把那些比较耗时且与UI无关的操作放到非主线程中去执行,避免这些耗时操作阻塞主线程导致界面操作起来很卡。比如:加载网络数据、本地存储、读取、更新大量数据这些情况都应该使用多线程。

三、没有GCD之前

  在GCD没有出现之前,在处理多线程的时候你可能用过(NSThread),(NSOperationQueue和NSInvocationOperation结合),或者是使用iOS提供的以下几个便捷方法:

- (void)performSelector:(SEL)aSelector onThread:(NSThread *)thr withObject:(id)arg waitUntilDone:(BOOL)wait NS_AVAILABLE(10_5, 2_0);

- (void)performSelectorInBackground:(SEL)aSelector withObject:(id)arg NS_AVAILABLE(10_5, 2_0);

- (void)performSelectorOnMainThread:(SEL)aSelector withObject:(id)arg waitUntilDone:(BOOL)wait;

以上几种方法都有一个共同的缺点就是代码比较分散,降低程序的可读性

例如下面这段代码:(版权为唐巧)

static NSOperationQueue * queue;

- (IBAction)someClick:(id)sender {
self.indicator.hidden = NO;
[self.indicator startAnimating];
queue = [[NSOperationQueue alloc] init];
NSInvocationOperation * op = [[[NSInvocationOperation alloc] initWithTarget:self selector:@selector(download) object:nil] autorelease];
[queue addOperation:op];
}

- (void)download {
NSURL * url = [NSURL URLWithString:@"http://www.youdao.com"];
NSError * error;
NSString * data = [NSString stringWithContentsOfURL:url encoding:NSUTF8StringEncoding error:&error];
if (data != nil) {
[self performSelectorOnMainThread:@selector(download_completed:) withObject:data waitUntilDone:NO];
} else {
NSLog(@"error when download:%@", error);
[queue release];
}
}

- (void) download_completed:(NSString *) data {
NSLog(@"call back");
[self.indicator stopAnimating];
self.indicator.hidden = YES;
self.content.text = data;
[queue release];
}


四、有了GCD以后

因为GCD采用了block的语法,因此我们可以把操作都放到block的代码块当中去执行(强烈建议在阅读本文之前先了解一些block的相关知识),还有一个优点就是GCD的API全部是c语言且是苹果强烈推荐使用,因此个人觉得在处理效率上应该相对其他几种方式要高一些。

如果使用GCD,以上3个方法都可以放到一起,如下所示:

// 原代码块一
self.indicator.hidden = NO;
[self.indicator startAnimating];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// 原代码块二
NSURL * url = [NSURL URLWithString:@"http://www.youdao.com"];
NSError * error;
NSString * data = [NSString stringWithContentsOfURL:url encoding:NSUTF8StringEncoding error:&error];
if (data != nil) {
// 原代码块三
dispatch_async(dispatch_get_main_queue(), ^{
[self.indicator stopAnimating];
self.indicator.hidden = YES;
self.content.text = data;
});
} else {
NSLog(@"error when download:%@", error);
}
});


五、系统提供的dispatch方法

乍一看,gcd的语法貌似很复杂,其实很简单,苹果为了方便我们使用GCD,提供了包括后台执行、主线程执行、延后执行等一系列方法具体如下:

//  后台执行:
dispatch_async(dispatch_get_global_queue(0, 0), ^{
// something
});
// 主线程执行:
dispatch_async(dispatch_get_main_queue(), ^{
// something
});
// 一次性执行:
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
// code to be executed once
});
// 延迟2秒执行:
double delayInSeconds = 2.0;
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC);
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
// code to be executed on the main queue after delay
});


dispatch_queue_t 也可以自己定义,如要要自定义queue,可以用dispatch_queue_create方法,示例如下:

dispatch_queue_t urls_queue = dispatch_queue_create("blog.devtang.com", NULL);
dispatch_async(urls_queue, ^{
// your code
});
dispatch_release(urls_queue);


两个线程并行

并行队列是不允许自己创建的,系统中存在三个不同优先级的并行队列。并行队列依旧按照任务添加的顺序启动任务,但是,后一个任务无须等待前一个任务执行完毕,而是启动第一个任务后,立即启动下一个任务。至于同一时刻允许同时运行多少个任务有系统决定。任务各自运行在并行队列为他们提供的独立线程上,并行队列中同时运行多少个任务,就必须维护多少个线程。

UInt32 loopCount = 1000;
UInt32 loopCountFirst = 10000000;
void (^taskFirst)(void) = ^{
NSLog(@"taskFirst 任务开始执行\r\n");
//延长taskFirst的运行时间
for (UInt32 i = 0; i < loopCountFirst; i++) {
}
NSLog(@"taskFirst 任务结束\r\n");
};
void (^taskSecond)(void) = ^{
NSLog(@"taskSecond任务开始执行\r\n");
for (UInt32 i = 0; i < loopCount; i ++) {
}
NSLog(@"taskSecond 任务结束\r\n");
};
dispatch_queue_t concurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(concurrentQueue, taskFirst);
NSLog(@"taskfirst 已经加入队列\r\n");
dispatch_async(concurrentQueue, taskSecond);
NSLog(@"tasksecond 已经加入队列\r\n");


另外,GCD还有一些高级用法,例如让后台2个线程并行执行,然后等2个线程都结束后,再汇总执行结果。这个可以用dispatch_group, dispatch_group_async 和 dispatch_group_notify来实现,示例如下:

dispatch_group_t group = dispatch_group_create();
dispatch_group_async(group, dispatch_get_global_queue(0,0), ^{
// 并行执行的线程一
});
dispatch_group_async(group, dispatch_get_global_queue(0,0), ^{
// 并行执行的线程二
});
dispatch_group_notify(group, dispatch_get_global_queue(0,0), ^{
// 汇总结果
});


六、总结

GCD极大地方便了iOS开发者使用多线程来完成数据与UI的交互,且充分利用了当今处理器的多核功能,既提高了效率又方便了使用。

非常感谢唐巧的一篇gcd使用的文章,此文中有些内容本人觉得无法比唐巧写得好变摘录过来,敬请谅解!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: