IOS学习之路八(GCD与多线程)

  GCD,全称Grand Central Dispath,是苹果开发的一种支持并行操作的机制。它的主要部件是一个FIFO队列和一个线程池,前者用来添加任务,后者用来执行任务。

     GCD中的FIFO队列称为dispatch queue,它可以保证先进来的任务先得到执行(但不保证一定先执行结束)。

     通过与线程池的配合,dispatch queue分为下面两种:

  •      Serial Dispatch Queue -- 线程池只提供一个线程用来执行任务,所以后一个任务必须等到前一个任务执行结束才能开始。
  •      Concurrent Dispatch Queue -- 线程池提供多个线程来执行任务,所以可以按序启动多个任务并发执行。

    1. Basic Management

         我们可以通过dispatch_queue_cretae来创建队列,然后用dispatch_release释放。比如下面两段代码分别创建串行队列和并行队列:

    dispatch_queue_t serialQ = dispatch_queue_create("eg.gcd.SerialQueue", DISPATCH_QUEUE_SERIAL);
    dispatch_async(serialQ, ^{
        // Code here
    });
    dispatch_release(serialQ);
    
    dispatch_queue_t concurrentQ = dispatch_queue_create("eg.gcd.ConcurrentQueue", DISPATCH_QUEUE_CONCURRENT);
    dispatch_async(concurrentQ, ^{
        // Code here
    });
    dispatch_release(concurrentQ);
    
     而系统默认就有一个串行队列main_queue和并行队列global_queue:

    [cpp]  view plain copy
    1. dispatch_queue_t globalQ = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);  
    2. dispatch_queue_t mainQ = dispatch_get_main_queue();  

         通常,我们可以在global_queue中做一些long-running的任务,完成后在main_queue中更新UI,避免UI阻塞,无法响应用户操作:

    [cpp]  view plain copy
    1. dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{  
    2.     // long-running task  
    3.     dispatch_async(dispatch_get_main_queue(), ^{  
    4.         // update UI  
    5.     });  
    6. });  

         上面提到dispatch_async这个接口,用来提交blcok给指定queue进行异步执行。这个接口会在成功提交block后立即返回,然后继续执行下去。由于block是定义在栈上的,所以需要将其复制到堆上,见这里

         与之相对应的是dispatch_sync接口,提交block以供同步执行。这个接口会等到block执行结束才返回,所以不需要复制block。So,如果在调用该接口在当前queue上指派任务,就会导致deadlock。维基百科上给了段示例代码:

    [cpp]  view plain copy
    1. dispatch_queue_t exampleQueue = dispatch_queue_create("com.example.unique.identifier", NULL );  
    2. dispatch_sync( exampleQueue,^{  
    3.   dispatch_sync( exampleQueue,^{  
    4.     printf("I am now deadlocked...\n");  
    5.   });});  
    6. dispatch_release( exampleQueue );  
         如果追求的是并发,那么dispatch_sync有什么用呢?关于dispatch_sync的用途,StackOverFlow是这样讨论的:

    Can anyone explain with really clear use cases what the purpose of dispatch_sync in GCD is for? I can't understand where and why I would have to use this.

    高手回答:

    You use it when you want to execute a block and wait for the results.

    One example of this is the pattern where you're using a dispatch queue instead of locks for synchronization. For example, assume you have a shared NSMutableArray a, with access mediated by dispatch queue q. A background thread might be appending to the array (async), while your foreground thread is pulling the first item off (synchronously):

    NSMutableArray *a = [[NSMutableArray alloc] init];
    // All access to `a` is via this dispatch queue!
    dispatch_queue_t q = dispatch_queue_create("com.foo.samplequeue", NULL);
    
    dispatch_async(q, ^{ [a addObject:something]; }); // append to array, non-blocking
    
    __block Something *first = nil;            // "__block" to make results from block available
    dispatch_sync(q, ^{                        // note that these 3 statements...
            if ([a count] > 0) {               // ...are all executed together...
                 first = [a objectAtIndex:0];  // ...as part of a single block...
                 [a removeObjectAtIndex:0];    // ...to ensure consistent results
            }
    });



    下面附上一个Demo  :(后台队列下载图片,当下载完后,调用主线程在前台显示)

    在Concoller中:

    -(void)viewDidAppear:(BOOL)animated{
    
    
        dispatch_queue_t concurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
        dispatch_async(concurrentQueue, ^{
            __block UIImage *image = nil;
            dispatch_sync(concurrentQueue, ^{
                /* 下载图片 */
               
                NSString *urlAsString = @"http://images.apple.com/mac/home/images/promo_lead_macbook_air.jpg";
               NSURL *url = [NSURL URLWithString:urlAsString];
                NSURLRequest *urlRequest = [NSURLRequest requestWithURL:url];
                NSError *downloadError = nil;
                NSData *imageData = [NSURLConnection sendSynchronousRequest:urlRequest returningResponse:nil error:&downloadError];
                if (downloadError == nil && imageData != nil){
                   image = [UIImage imageWithData:imageData];
                } else if(downloadError!=nil){
                    NSLog(@"Error happened = %@", downloadError);
                }else {
                    NSLog(@"No data could get downloaded from the URL.");
                }
            });
            //在主队列中把图片展示给用户
            dispatch_sync(dispatch_get_main_queue(), ^{
                
                if (image != nil){
                    /* 创建一个UIImageView */
                    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.");
                } });
         }); 
    
    }
    


    运行结果:













评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值