一: GCD(Grand Central Dispatch)->中樞調(diào)度器
1>. 存在的庫:
GCD存在于libdispatch.dylib這個庫中但狭,這個調(diào)度庫包含了GCD的所有的東西史汗,但任何IOS程序伴榔,默認(rèn)就加載了這個庫,在程序運行的過程中會動態(tài)的加載這個庫色迂,不需要我們手動導(dǎo)入。
. GCD是純C語言的,因此我們在編寫GCD相關(guān)代碼的時候幢炸,面對的函數(shù),而不是方法拒贱。
. GCD中的函數(shù)大多數(shù)都以dispatch開頭宛徊。
2>. 任務(wù)和隊列:
GCD中有2個核心概念
(1)任務(wù):執(zhí)行什么操作
(2)隊列:用來存放任務(wù)
GCD的使用就2個步驟
(1)定制任務(wù)
(2)確定想做的事情
3>. 執(zhí)行任務(wù):
.GCD中有2個用來執(zhí)行任務(wù)的函數(shù)
說明:把右邊的參數(shù)(任務(wù))提交給左邊的參數(shù)(隊列)進(jìn)行執(zhí)行。
(1)用同步的方式執(zhí)行任務(wù) dispatch_sync(dispatch_queue_t queue, dispatch_block_t block);
參數(shù)說明:
queue:隊列
block:任務(wù)
(2)用異步的方式執(zhí)行任務(wù) dispatch_async(dispatch_queue_t queue, dispatch_block_t block);
4>. 同步和異步的區(qū)別
同步:在當(dāng)前線程中執(zhí)行
異步:在另一條線程中執(zhí)行
5>. 隊列的類型:
(1)并發(fā)隊列(Concurrent Dispatch Queue)
可以讓多個任務(wù)并發(fā)(同時)執(zhí)行(自動開啟多個線程同時執(zhí)行任務(wù))并發(fā)功能只有在異步(dispatch_async)函數(shù)下才有效
(2)串行隊列(Serial Dispatch Queue)
讓任務(wù)一個接著一個地執(zhí)行(一個任務(wù)執(zhí)行完畢后逻澳,再執(zhí)行下一個任務(wù))
GCD中獲得串行有2種途徑
6>. 創(chuàng)建隊列:
o1>. 串行隊列:
(1)使用dispatch_queue_create函數(shù)創(chuàng)建串行隊列
dispatch_queue_t dispatch_queue_create(const char *label, dispatch_queue_attr_t attr); // 隊列名稱闸天, 隊列屬性,一般用NULL即可
示例:
dispatch_queue_t queue = dispatch_queue_create("wendingding", NULL); // 創(chuàng)建
dispatch_release(queue); // 非ARC需要釋放手動創(chuàng)建的隊列
(2)使用主隊列(跟主線程相關(guān)聯(lián)的隊列)
主隊列是GCD自帶的一種特殊的串行隊列,放在主隊列中的任務(wù)斜做,都會放到主線程中執(zhí)行
使用dispatch_get_main_queue()獲得主隊列
示例:
dispatch_queue_t queue = dispatch_get_main_queue();
o2>. 并行隊列:
GCD默認(rèn)已經(jīng)提供了全局的并發(fā)隊列苞氮,供整個應(yīng)用使用,不需要手動創(chuàng)建
使用dispatch_get_global_queue函數(shù)獲得全局的并發(fā)隊列
dispatch_queue_t dispatch_get_global_queue(dispatch_queue_priority_t priority,unsigned long flags); // 此參數(shù)暫時無用瓤逼,用0即可
示例:
這個參數(shù)是留給以后用的笼吟,暫時用不上,傳個0霸旗。
第一個參數(shù)為優(yōu)先級贷帮,這里選擇默認(rèn)的。獲取一個全局的默認(rèn)優(yōu)先級的并發(fā)隊列诱告。
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); // 獲得全局并發(fā)隊列
<說明>. 全局并發(fā)隊列的優(yōu)先級:
#define DISPATCH_QUEUE_PRIORITY_HIGH 2 // 高
#define DISPATCH_QUEUE_PRIORITY_DEFAULT 0 // 默認(rèn)(中)
#define DISPATCH_QUEUE_PRIORITY_LOW (-2) // 低
#define DISPATCH_QUEUE_PRIORITY_BACKGROUND INT16_MIN // 后臺
7>. 各種隊列的執(zhí)行效果:
<說明>. 同步函數(shù)與異步函數(shù):
(1). 用GCD同步執(zhí)行非UI相關(guān)的任務(wù)
目的:想要執(zhí)行那些不包含任何UI相關(guān)代碼的同步任務(wù)
方案:使用dispatch_sync 函數(shù)撵枢。
(2). 在GCD上異步執(zhí)行非UI相關(guān)任務(wù)
目的:你想要在GCD的幫助下能夠異步執(zhí)行非UI相關(guān)任務(wù)。
方案:主隊列蔬啡、串行隊列和并發(fā)隊列上異步執(zhí)行代碼塊才能見識到GCD的真正實力诲侮。(本書作者說,GCD會是多線程應(yīng)用的未來箱蟆,并將完全取代現(xiàn)代應(yīng)用中的線程)沟绪,千萬注意:不要再主隊列中使用同步執(zhí)行函數(shù)dispatch_sync
要在分派隊列上執(zhí)行異步任務(wù),你必須使用下面的這些函數(shù)中的其中一個:
dispatch_async 函數(shù)(在分派隊列上執(zhí)行一個 Block Object.)或者
dispatch_async_f函數(shù)(在分派隊列上執(zhí)行一個C函數(shù))
8>. 小結(jié)
同步函數(shù)不具備開啟線程的能力空猜,無論是什么隊列都不會開啟線程绽慈;異步函數(shù)具備開啟線程的能力恨旱,開啟幾條線程由隊列決定(串行隊列只會開啟一條新的線程,并發(fā)隊列會開啟多條線程)坝疼。
同步函數(shù)
(1)并發(fā)隊列:不會開線程
(2)串行隊列:不會開線程
異步函數(shù)
(1)并發(fā)隊列:能開啟N條線程
(2)串行隊列:開啟1條線程
補充:
凡是函數(shù)中搜贤,各種函數(shù)名中帶有create\copy\new\retain等字眼,都需要在不需要使用這個數(shù)據(jù)的時候進(jìn)行release钝凶。
GCD的數(shù)據(jù)類型在ARC的環(huán)境下不需要再做release仪芒。
CF(core Foundation)的數(shù)據(jù)類型在ARC環(huán)境下還是需要做release。
異步函數(shù)具備開線程的能力耕陷,但不一定會開線程
二: NSThread的使用:
<特點>:
優(yōu)點:NSThread 比其他兩個輕量級
缺點:需要自己管理線程的生命周期掂名,線程同步。線程同步對數(shù)據(jù)的加鎖會有一定 的系統(tǒng)開銷
1>. 創(chuàng)建:
- (id)initWithTarget:(id)target selector:(SEL)selector object:(id)argument
+ (void)detachNewThreadSelector:(SEL)aSelector toTarget:(id)aTarget withObject:(id)anArgument
第一個是實例方法哟沫,第二個是類方法
<selector方法實現(xiàn)>:
1饺蔑、[NSThread detachNewThreadSelector:@selector(doSomething:) toTarget:self withObject:nil];
2、NSThread* myThread = [[NSThread alloc] initWithTarget:self
selector:@selector(doSomething:)
object:nil];
[myThread start];
例子>.下載圖片的例子:
-(void)downloadImage:(NSString *) url{
NSData *data = [[NSData alloc] initWithContentsOfURL:[NSURL URLWithString:url]];
UIImage *image = [[UIImage alloc]initWithData:data];
if(image == nil){
}else{
[self performSelectorOnMainThread:@selector(updateUI:) withObject:image waitUntilDone:YES];
}
}
-(void)updateUI:(UIImage*) image{
self.imageView.image = image;
}
- (void)viewDidLoad
{
[super viewDidLoad];
//[NSThread detachNewThreadSelector:@selector(downloadImage:) toTarget:self withObject:kURL];
NSThread *thread = [[NSThread alloc]initWithTarget:self selector:@selector(downloadImage:) object:kURL];
[thread start];
}
2>. 線程間通訊:
線程下載完圖片后怎么通知主線程更新界面呢嗜诀?
[self performSelectorOnMainThread:@selector(updateUI:) withObject:image waitUntilDone:YES];
performSelectorOnMainThread是NSObject的方法猾警,除了可以更新主線程的數(shù)據(jù)外,還可以更新其他線程的比如:用:performSelector:onThread:withObject:waitUntilDone:
三:NSOperation和NSOperationQueue的使用:
1>. 使用NSOperation的方式:
(1). 用定義好的子類:
NSInvocationOperation 和 NSBlockOperation隆敢。
(2). 繼承NSOperation:
如果你也熟悉Java发皿,NSOperation就和java.lang.Runnable接口很相似。和Java的Runnable一樣筑公,NSOperation也是設(shè)計用來擴展的雳窟,只需繼承重寫NSOperation的一個方法main。相當(dāng)與java 中Runnalbe的Run方法匣屡。然后把NSOperation子類的對象放入NSOperationQueue隊列中封救,該隊列就會啟動并開始處理它。
2>. 例子>.
(1). NSInvocationOperation例子:
- (void)viewDidLoad
{
[super viewDidLoad];
NSInvocationOperation *operation = [[NSInvocationOperation alloc]initWithTarget:self selector:@selector(downloadImage:) object:kURL];
NSOperationQueue *queue = [[NSOperationQueue alloc]init];
[queue addOperation:operation];
// Do any additional setup after loading the view, typically from a nib.
}
-(void)downloadImage:(NSString *)url{
NSLog(@"url:%@", url);
NSURL *nsUrl = [NSURL URLWithString:url];
NSData *data = [[NSData alloc]initWithContentsOfURL:nsUrl];
UIImage * image = [[UIImage alloc]initWithData:data];
[self performSelectorOnMainThread:@selector(updateUI:) withObject:image waitUntilDone:YES];
}
-(void)updateUI:(UIImage*) image{
self.imageView.image = image;
}
(2). 繼承NSOperation:
在.m文件中實現(xiàn)main方法捣作,main方法編寫要執(zhí)行的代碼即可.
3>. 如何控制線程池中的線程數(shù)誉结?
隊列里可以加入很多個NSOperation, 可以把NSOperationQueue看作一個線程池,可往線程池中添加操作(NSOperation)到隊列中券躁。線程池中的線程可看作消費者惩坑,從隊列中取走操作,并執(zhí)行它也拜。
通過下面的代碼設(shè)置:
[queue setMaxConcurrentOperationCount:5];
線程池中的線程數(shù)以舒,也就是并發(fā)操作數(shù)。默認(rèn)情況下是-1慢哈,-1表示沒有限制蔓钟,這樣會同時運行隊列中的全部的操作。