iOS多線程開發之GCD 用法入門

咱們知道,在iOS中進行多線程編程,主要有三種方式:【NSThread】、【NSOperation】和【GCD】。其中又以【GCD】爲蘋果官方最爲推薦。本文將利用一個簡單的demo,簡述GCD的用法入門,以及本人對GCD的一點膚淺理解和學習心得。html

先把參考文章列出:編程

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.htmiphone

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

這裏重點推薦 http://www.dreamingwish.com/frontui/article/default/the-of-of-of-gcd-tutorial.html GCD系列教程!async

 

關於【NSThread】和【NSOperation】其實在我以前的博文中有所涉及,好比個人這篇博文http://www.cnblogs.com/pigpigDD/p/3975852.html 使用了NSThread方式進行子線程NSTimer計時;以及個人這片博文:http://www.cnblogs.com/pigpigDD/p/3956308.html 使用了NSOperation子類進行網絡請求。ide

下面來講說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中有不少細節,和一些進階的東西,仍是值得好好研究學習的。爭取在之後的文章中,慢慢概括總結出來。

相關文章
相關標籤/搜索