GCD實踐——序列佇列/併發佇列與iOS多執行緒詳解
GCD(Grand Central Dispatch),是蘋果提供的一個解決多執行緒開發的解決方案。GCD會自動管理執行緒的生命週期(建立執行緒,排程任務,銷燬執行緒),完全不需要我們管理,我們只需要告訴幹什麼就行。同時GCD使用block來進行任務的執行,用起來非常方便、靈活。本篇部落格我們主要將GCD,其他的多執行緒實現方式還有NSThread、NSOperationQueue,我們將會在以後的部落格中講解。
這裡我們要提到一個概念:【任務】。就是操作,就是你要執行的一段程式碼,在GCD中就是一個Block,所以新增任務十分方便。
【同步執行】:只要是同步執行的任務,都會在當前執行緒執行,不會另開執行緒。所以說網路請求等耗時操作一般不使用同步,而是非同步,否則會阻塞主執行緒,介面會卡住。
【非同步執行】:只要是非同步任務執行的任務,都會另開執行緒,在別的執行緒執行。
同步(sync)和非同步(async)的主要區別在於會不會阻塞當前執行緒,直到Block中的任務執行完畢。
如果是同步(sync)操作,它會阻塞當前執行緒並等待Block中的任務執行完畢,然後當前執行緒才會繼續往下執行(因為同步操作沒有開新執行緒,是在主執行緒中執行的,所以會阻塞)。
如果是非同步(async)操作,當前執行緒會直接往下執行,他不會阻塞當前執行緒(因為非同步操作是在另一個執行緒中執行的,所以不會阻塞主執行緒)。
佇列:用於存放任務,一共有兩種佇列:序列佇列和並行佇列。
1.序列佇列(private dispatch queue)一次只執行一個執行緒,按照新增到佇列的順序依次執行;
2.並行佇列(global dispatch queue)一次可以執行多個執行緒,執行緒的執行沒有先後順序。根據同步或者非同步有不同的執行方式。放到並行佇列的任務,GCD也會FIFO的取出來,但不同的是,他取出來一個就會放到別的執行緒,然後再取出來一個又放到另一個執行緒。
3.Main dispatch queue:UI介面所在的執行緒佇列是主執行緒。
【序列佇列示例】
(1)首先匯入GCD封裝後的程式碼,可以從我的專案中直接複製,總共9個檔案:其實個人推薦使用iOS原生的GCD,請移步《iOS開發——GCD的使用與多執行緒開發淺析》這篇部落格。
。
(2)ViewController中的實現如下:
#import "ViewController.h" #import "GCD.h" @interface ViewController () @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; //執行序列佇列; [self serailQueue]; } //序列佇列; - (void)serailQueue{ //創建出佇列; GCDQueue *queue = [[GCDQueue alloc] initSerial]; //執行佇列中的執行緒; [queue execute:^{ NSLog(@"1"); }]; [queue execute:^{ NSLog(@"2"); }]; [queue execute:^{ NSLog(@"3"); }]; [queue execute:^{ NSLog(@"4"); }]; [queue execute:^{ NSLog(@"5"); }]; } @end
(3)執行結果如下:
。
(4)結果分析
輸出結果和我們的預期一樣,是按照新增到佇列的順序執行的。
【並行佇列示例】
(1)同樣需要引入GCD原始碼,在ViewController中的實現如下:
#import "ViewController.h"
#import "GCD.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
//執行併發佇列;
[self concurrent];
}
//併發佇列;
- (void)concurrent{
//創建出佇列;
GCDQueue *queue = [[GCDQueue alloc] initConcurrent];
//執行佇列中的執行緒;
[queue execute:^{
NSLog(@"1");
}];
[queue execute:^{
NSLog(@"2");
}];
[queue execute:^{
NSLog(@"3");
}];
[queue execute:^{
NSLog(@"4");
}];
[queue execute:^{
NSLog(@"5");
}];
}
@end
(2)結果輸出:
。
(3)結果分析:
輸出結果和我們預期的一樣,執行的順序是無序的。
【UI介面更新】
(1)使用GCD,我們可以來進行網路操作或者下載請求,然後更新UI。這一系列操作是序列操作,需要有一定的順序。在這裡我使用了同步請求。在ViewController中實現如下:
#import "ViewController.h"
#import "GCD.h"
@interface ViewController ()
@property(strong,nonatomic) UIImage *image;
@property (weak, nonatomic) IBOutlet UIImageView *imageView;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
//globalqueue其實就是並行佇列。
[GCDQueue executeInGlobalQueue:^{
//處理業務邏輯
NSString *url = @"http://imgsrc.baidu.com/forum/w%3D580/sign=2e824145d2c8a786be2a4a065708c9c7/5a8e72094b36acaf254077437fd98d1000e99c4a.jpg";
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:url]];
NSData *picData = [NSURLConnection sendSynchronousRequest:request
returningResponse:nil
error:nil];
NSLog(@"處理業務邏輯");
//獲取圖片;
self.image = [UIImage imageWithData:picData];
[GCDQueue executeInMainQueue:^{
NSLog(@"更新UI");
//更新UI
[self.imageView setImage:self.image];
}];
}];
}
@end
(2)注意,我在storyboard中放了一個ImageView控制元件。執行效果如下:
。