zoukankan      html  css  js  c++  java
  • iOS多线程开发之GCD 用法入门

    我们知道,在iOS中进行多线程编程,主要有三种方式:【NSThread】、【NSOperation】和【GCD】。其中又以【GCD】为苹果官方最为推荐。本文将利用一个简单的demo,简述GCD的用法入门,以及本人对GCD的一点肤浅理解和学习心得。

    先把参考文章列出:

    http://www.cnblogs.com/kenshincui/p/3983982.html

    http://www.cnblogs.com/sunfrog/p/3305614.html

    http://mobile.51cto.com/iphone-446101.htm

    http://mobile.51cto.com/iphone-402964.htm

    http://mobile.51cto.com/iphone-386596.htm

    http://www.cnblogs.com/yangecnu/p/3164167.html

    这里重点推荐 http://www.dreamingwish.com/frontui/article/default/the-of-of-of-gcd-tutorial.html GCD系列教程!

    关于【NSThread】和【NSOperation】其实在我之前的博文中有所涉及,比如我的这篇博文http://www.cnblogs.com/pigpigDD/p/3975852.html 使用了NSThread方式进行子线程NSTimer计时;以及我的这片博文:http://www.cnblogs.com/pigpigDD/p/3956308.html 使用了NSOperation子类进行网络请求。

    下面来说说GCD。

    GCD的使用中,最基本也是最核心的概念就是dispatch queue队列。dispatch queue是一个对象,它可以接受任务,并将任务以先到先执行的顺序来执行。dispatch queue可以是并发的或串行的。并发任务会像NSOperationQueue那样基于系统负载来合适地并发进行,串行队列同一时间只执行单一任务。并且,它可以嵌套使用。

    1,并行、串行、并行的概念:

    并发:在单核心上,多个线程,交替轮换地执行任务命令,每次执行一个任务

    串行:在单核心上,一个线程,顺次地执行任务命令,每次执行一个任务

    并行:在多核心上,多个线程,同时交替轮换执行任务命令,每次有多个任务同时在多个核心上执行

    2,GCD中的三种队列类型

    2.1,The main queue: 与主线程功能相同。实际上,提交至main queue的任务会在主线程中执行。main queue可以调用dispatch_get_main_queue()来获得。因为main queue是与主线程相关的,所以这是一个串行队列。

    2.2,Global queues: 全局队列是并发队列,并由整个进程共享。进程中存在三个全局队列:高、中(默认)、低三个优先级队列。可以调用dispatch_get_global_queue函数传入优先级来访问队列。

    2.3,用户队列: 用户队列 (GCD并不这样称呼这种队列, 但是没有一个特定的名字来形容这种队列,所以我们称其为用户队列) 是用函数 dispatch_queue_create 创建的队列. 这些队列是串行的,可以用来完成同步机制, 有点像传统线程中的mutex。

            2.3.1,dispatch_queue_t queue = dispatch_queue_create("com.dispatch.serial",DISPATCH_QUEUE_SERIAL); 生成一个串行队列,队列中的block按照先进先出(FIFO)的顺序去执行,实际上为单线程执行。第一个参数是队列的名称,在调试程序时会非常有用,所有尽量不要重名了。

            2.3.2,dispatch_queue_t queue = dispatch_queue_create("com.dispatch.concurrent", DISPATCH_QUEUE_CONCURRENT); 生成一个并发执行队列,block被分发到多个线程去执行。

    3,分别用串行队列和并发队列演示一个demo

    3.1,串行队列加载一系列图片

    串行队列,正如前面所说的,就是队列中一系列的任务,按照先进先处理的方式,“排队按序”执行。这里使用了我自己创建了一个串行队列。

     1 //
     2 //  MainView.m
     3 //  GCDDemo
     4 //
     5 //  Created by pigpigdaddy on 14-9-29.
     6 //  Copyright (c) 2014年 pigpigdaddy. All rights reserved.
     7 //
     8 
     9 #import "MainView.h"
    10 
    11 #define ROW_COUNT 5
    12 #define COLUMN_COUNT 3
    13 #define IMAGEVIEW_BASE_TAG 100
    14 
    15 @interface MainView()
    16 
    17 @property (nonatomic, strong)NSMutableArray *dataArray;
    18 @property (nonatomic, strong)UIScrollView *scrollView;
    19 
    20 @end
    21 
    22 @implementation MainView
    23 
    24 - (id)initWithFrame:(CGRect)frame
    25 {
    26     self = [super initWithFrame:frame];
    27     if (self) {
    28         // Initialization code
    29         [self initData];
    30         [self initView];
    31     }
    32     return self;
    33 }
    34 
    35 - (void)initData
    36 {
    37     // 存储图片地址的数组
    38     self.dataArray = [[NSMutableArray alloc] init];
    39     for (int i = 0; i<ROW_COUNT*COLUMN_COUNT; i++) {
    40         [self.dataArray addObject:[NSString stringWithFormat:@"http://images.cnblogs.com/cnblogs_com/pigpigDD/616506/o_%d.png", i+1]];
    41     }
    42 }
    43 
    44 - (void)initView
    45 {
    46     // 创建scrollView
    47     self.scrollView = [[UIScrollView alloc] initWithFrame:self.bounds];
    48     [self addSubview:self.scrollView];
    49     
    50     // 创建用于显示的UIImageView
    51     for (int i = 0; i<ROW_COUNT; i++) {
    52         for (int j = 0; j<COLUMN_COUNT; j++) {
    53             UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(100*(j%COLUMN_COUNT)+5, 110*(i%ROW_COUNT)+5, 100, 110)];
    54             imageView.tag = IMAGEVIEW_BASE_TAG+j+i*3;
    55             [self.scrollView addSubview:imageView];
    56         }
    57     }
    58     self.scrollView.contentSize = CGSizeMake(320, 575);
    59     
    60     // 开始加载的按钮
    61     UIButton *button = [UIButton buttonWithType:UIButtonTypeSystem];
    62     button.backgroundColor = [UIColor lightGrayColor];
    63     button.frame = CGRectMake(100, self.bounds.size.height-50,80, 30);
    64     [button setTitle:@"开始加载" forState:UIControlStateNormal];
    65     [button addTarget:self action:@selector(loadImage) forControlEvents:UIControlEventTouchUpInside];
    66     [self addSubview:button];
    67 }
    68 
    69 - (void)downImage:(int)index{
    70     // 获取图片
    71     NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:@"%@", [self.dataArray objectAtIndex:index]]];
    72     NSData *data = [NSData dataWithContentsOfURL:url];
    73     
    74     UIImage *image = [UIImage imageWithData:data];
    75     
    76     // 获取主线程队列
    77     dispatch_queue_t mainQueue = dispatch_get_main_queue();
    78     // 在主线程中更新下载好的图片
    79     dispatch_async(mainQueue, ^{
    80         UIImageView *imageView = (UIImageView *)[self viewWithTag:IMAGEVIEW_BASE_TAG + index];
    81         imageView.image = image;
    82     });
    83 }
    84 
    85 
    86 - (void)loadImage
    87 {
    88     // 创建一个串行队列
    89     dispatch_queue_t serialQueue = dispatch_queue_create("com.dispatch.serialQueue", DISPATCH_QUEUE_SERIAL);
    90     for (int i = 0; i<ROW_COUNT*COLUMN_COUNT; i++) {
    91         dispatch_async(serialQueue, ^{
    92             [self downImage:i];
    93         });
    94     }
    95 }
    96 
    97 @end

    这里的MainView是我自定义的一个继承自UIView的类,他在window的rootViewController实例中初始化并加载。

    效果:

    可以看到,当点击“开始加载”按钮后,图片按照设置的顺序依次下载并显示。同时上下滑动scrollView,由于下载图片数据不发生在主线程,所以不会发生卡顿的现象。

    3.2,并发队列加载一系列图片

    采用并发队列,图片无序下载并显示。这里只需要修改-(void)loadImage函数实现即可:

     1 -(void)loadImage{
     2     int count=ROW_COUNT*COLUMN_COUNT;
     3     
     4     // 使用全局并发队列
     5     //dispatch_queue_t globalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
     6     
     7     // 使用自己创建的并发队列
     8     dispatch_queue_t concurrentQueue = dispatch_queue_create("com.dispatch.concurrentQueue", DISPATCH_QUEUE_CONCURRENT);
     9     //创建多个线程用于填充图片
    10     for (int i=0; i<count; ++i) {
    11         //异步执行队列任务
    12         dispatch_async(concurrentQueue, ^{
    13             [self downImage:i];
    14         });
    15     }
    16 }

    正如2.2和2.3中所写的,并发队列可以使用全局并发队列,也可以使用自己创建的并发队列。

    效果如下:

    4,注意点:

    不论是串行队列还是并发队列,只有在异步调用的时候才是真正启用了多线程,使用同步调用则其实是在主线程上运行!你可以NSLog打出[NSThread currentThread];来分析。

    以上对GCD的基本用法,和一些基本概念做了归纳总结。我觉得其实GCD的基本使用是很简单的,但是GCD中有很多细节,和一些进阶的东西,还是值得好好研究学习的。争取在以后的文章中,慢慢归纳总结出来。

  • 相关阅读:
    PeerJS
    OpenEMM 2013 发布,电子邮件营销软件
    feh 2.9 发布,图像查看器
    PyPyODBC 0.9.2发布 纯Python实现的pyodbc替代库
    MariaDB 5.5.29, 5.3.12, 5.2.14, 5.1.67
    CouchDB 1.3.0的新特性以及算法的强化
    Boost 1.53.0 发布,可移植的C++标准库
    ActiveMQ 5.8.0 发布,JMS 消息服务器
    MySQL 5.5.30 发布
    CloverETL Designer 3.3.1 发布
  • 原文地址:https://www.cnblogs.com/pigpigDD/p/4000959.html
Copyright © 2011-2022 走看看