首页 > 代码库 > GCD6: 在GCD上异步执行非UI相关任务

GCD6: 在GCD上异步执行非UI相关任务

讨论:在主队列、串行队列和并发队列上异步执行代码块才能见识到 GCD 的真正实力。

要在分派队列上执行异步任务,你必须使用下面这些函数中的其中一个:

dispatch_async为了异步执行向分派队列提交一个 Block Object(2 项都通过参数指定)

dispatch_async_f为了异步执行向分派队列提交一个 C 函数和一个上下文引用(3 项通过参数参数指定) 

dispatch_async 和dispatch_sync的区别

dispatch_sync(),同步添加操作。他是等待添加进队列里面的操作完成之后再继续执行。

dispatch_queue_t concurrentQueue = dispatch_queue_create("my.concurrent.queue", DISPATCH_QUEUE_CONCURRENT);    NSLog(@"1");    dispatch_sync(concurrentQueue, ^(){        NSLog(@"2");        [NSThread sleepForTimeInterval:10];        NSLog(@"3");    });    NSLog(@"4");输出 :        11:36:25.313 GCDSeTest[544:303] 111:36:25.313 GCDSeTest[544:303] 211:36:30.313 GCDSeTest[544:303] 3//模拟长时间操作11:36:30.314 GCDSeTest[544:303] 4

dispatch_async ,异步添加进任务队列,它不会做任何等待

dispatch_queue_t concurrentQueue = dispatch_queue_create("my.concurrent.queue", DISPATCH_QUEUE_CONCURRENT);    NSLog(@"1");    dispatch_async(concurrentQueue, ^(){        NSLog(@"2");        [NSThread sleepForTimeInterval:5];        NSLog(@"3");    });    NSLog(@"4");输出: 11:42:43.820 GCDSeTest[568:303] 1 11:42:43.820 GCDSeTest[568:303] 4 11:42:43.820 GCDSeTest[568:1003] 2 11:42:48.821 GCDSeTest[568:1003] 3//模拟长时间操作时间

实例:

写一个 iOS APP, 它能从网络的 URL 上下载一个图片。下载完 成之后,APP 应该将图片展示给用户。 

 

1、我们在并发队列上异步的启动一个 block object。

2、在这个 block 中我们使用 dispatch_sync 函数来启动另一个 Block Object,以从 URL 上下载图片。我这样做的目的是想让并发队列中剩余的代码能够等到图片下载完成之后在继续执行。从一个异步代码块上同步下载一个 URL 可以保持这个队列运行同步函数,而不是主线程。当我们从主线程角度来看的话整个运作仍是异步的。我们关心的问题是在下载图片的过程中没有阻塞主线程。

3、图片下载完毕后,为了在 UI 上将图片展示给用户,我们会在主线程上同步执行一个 Block 

 

我们计划的框架:
dispatch_queue_t concurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); 
dispatch_async(concurrentQueue, ^{__block UIImage *image = nil;dispatch_sync(concurrentQueue, ^{/* Download the image here */});dispatch_sync(dispatch_get_main_queue(), ^{/* Show the image to the user here on the main queue*/});});

详细代码为:

- (void)viewDidLoad {    [super viewDidLoad];    // Do any additional setup after loading the view, typically from a nib.    dispatch_queue_t concurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);    dispatch_async(concurrentQueue, ^{        __block UIImage *image = nil;        dispatch_sync(concurrentQueue, ^{            //开始下载图片            NSString *urlString = @"http://a.hiphotos.baidu.com/image/pic/item/eac4b74543a9822677de5a5c8982b9014a90ebaa.jpg";            NSURL *url = [NSURL URLWithString:urlString];            NSURLRequest *request = [NSURLRequest requestWithURL:url];            NSError *downloadError = nil;            NSData *imageData = http://www.mamicode.com/[NSURLConnection sendSynchronousRequest:request returningResponse:nil error:&downloadError];            if (downloadError == nil && imageData != nil) {                image = [UIImage imageWithData:imageData];                //获得了图片            }            else if (downloadError != nil){                NSLog(@"Error happended : %@",downloadError);            }else{                NSLog(@"No data could get downloaded from the URL");            }        });        dispatch_sync(dispatch_get_main_queue(), ^{            //主线程上展示图片            if (image != nil) {                UIImageView *imageView = [[UIImageView alloc]initWithFrame:self.view.bounds];                [imageView setImage:image];                [imageView setContentMode:UIViewContentModeScaleAspectFit];                [self.view addSubview:imageView];            }else{                NSLog(@"Image isn‘t downloaded. Nothing to display.");            }        });    });}

下面我们来看另一个例子:

假设我们在磁盘的一个文件内存储了 1000 个随机数字的数组,我们想把这个数组加载到内存,让数字按照升序排列然后展示给用户。
如果我们没有数组,那为什么我们不先创建一个数组然后再进行加载,最后展示出来呢? 

 


GCD6: 在GCD上异步执行非UI相关任务