GCD入门(二)啦

作者: 诺馨 | 来源:发表于2016-05-24 21:16 被阅读48次

    废话不多说,直接从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。
    其它待续。
    
    
    
    
    
    

    相关文章

      网友评论

        本文标题:GCD入门(二)啦

        本文链接:https://www.haomeiwen.com/subject/ilmzrttx.html