GCD
什么是GCD
- 全稱是Grand Central Dispatch粘室,可譯為“強(qiáng)大的調(diào)度器”
純C語言切威,提供了非常多強(qiáng)大的函數(shù)
GCD的優(yōu)勢
- GCD是蘋果公司為多核的并行運(yùn)算提出的解決方案
- GCD會自動利用更多的CPU內(nèi)核(比如雙核、四核)
- GCD會自動管理線程的生命周期(創(chuàng)建線程先朦、調(diào)度任務(wù)犬缨、銷毀線程)
- 程序員只需要告訴GCD想要執(zhí)行什么任務(wù),不需要編寫任何線程管理代碼
GCD的核心概念
任務(wù):想要做什么事情
隊(duì)列:執(zhí)行任務(wù)的順序
-
步驟:
- 寫好自己想要執(zhí)行的任務(wù)
- 放在隊(duì)列里等待執(zhí)行(FIFO,GCD會根據(jù)隊(duì)列的順序進(jìn)行自動取出執(zhí)行,并且根據(jù)情況創(chuàng)建線程)
隊(duì)列的類型
- 并發(fā)隊(duì)列
- 隊(duì)列里的任務(wù)會自動開啟多個線程并發(fā)執(zhí)行,但是需要異步函數(shù)的任務(wù)才有效
- 隊(duì)列只是影響任務(wù)執(zhí)行的方式,實(shí)際上并不能決定是否開啟新的線程,僅僅是并發(fā)隊(duì)列允許多個線程同時運(yùn)行,而串行隊(duì)列只能是一個一個任務(wù)在同一線程執(zhí)行.
- 如何創(chuàng)建并發(fā)隊(duì)列
//通過直接創(chuàng)建的方式創(chuàng)建,參數(shù)決定是否是并發(fā)隊(duì)列
//DISPATCH_QUEUE_CONCURRENT代表并發(fā)隊(duì)列
//DISPATCH_QUEUE_SERIAL或NULL代表串行隊(duì)列
//標(biāo)示符代表這個隊(duì)列的一個標(biāo)記
dispatch_queue_t queue = dispatch_queue_create("標(biāo)示符", DISPATCH_QUEUE_CONCURRENT);
//通過獲取全局隊(duì)列來獲得一個并發(fā)隊(duì)列
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
//這兩個參數(shù),第一個是優(yōu)先級一般用默認(rèn),第二個直接設(shè)為0 是一個保留標(biāo)記,實(shí)際作用不大
- 串行隊(duì)列
- 隊(duì)列里的任務(wù)會以串行的形式一個一個按順序執(zhí)行
- 如何創(chuàng)建串行隊(duì)隊(duì)列
//直接創(chuàng)建
//DISPATCH_QUEUE_SERIAL或NULL代表串行隊(duì)列
dispatch_queue_t queue = dispatch_queue_create("標(biāo)示符", DISPATCH_QUEUE_SERIAL);
//獲得主隊(duì)列,也是一種串行隊(duì)列
dispatch_queue_t queue = dispatch_get_main_queue();
- 同步函數(shù)與異步函數(shù)
- 異步函數(shù)具有創(chuàng)建線程的能力,同步函數(shù)并沒有.
- 同步函數(shù)如何創(chuàng)建
//queue代表你要放入的隊(duì)列
dispatch_sync(queue, ^{
//在這里寫要執(zhí)行的代碼
});
- 異步函數(shù)如何創(chuàng)建
//queue代表你要放入的隊(duì)列
dispatch_async(queue, ^{
//在這里寫要執(zhí)行的代碼
});
- 柵欄函數(shù)
//隔斷函數(shù),前面執(zhí)行完才會執(zhí)行這個函數(shù),這個函數(shù)執(zhí)行完才會執(zhí)行其他后面的函數(shù)
dispatch_barrier_async(dispatch_queue_t queue, dispatch_block_t block);
//全局并發(fā)情況下有問題
不同的隊(duì)列與函數(shù)的組合會有不同的效果
- 并行隊(duì)列+異步函數(shù):創(chuàng)建新的線程,并行執(zhí)行任務(wù)
- 并行隊(duì)列+同步函數(shù):沒有新的線程,串行執(zhí)行任務(wù)
- 串行隊(duì)列+異步函數(shù):創(chuàng)建新的線程,串行執(zhí)行任務(wù)
- 串行隊(duì)列+同步函數(shù):沒有新的線程,串行執(zhí)行任務(wù)
- 主隊(duì)列+異步函數(shù):沒有新的線程,串行執(zhí)行任務(wù)
- 主隊(duì)列+同步函數(shù):沒有新的線程,串行執(zhí)行任務(wù)
線程之間通信示例
- 一個示例,簡單的表示了如何在不同的隊(duì)列之間做事情
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
//在這里寫上放在全局隊(duì)列的代碼
dispatch_async(dispatch_get_main_queue(), ^{
//寫在這里就是執(zhí)行主函數(shù)的代碼
});
});
IOS上常見的延時代碼
//調(diào)用NSObject的方法
[self performSelector:@selector(run) withObject:nil afterDelay:2.0];
// 2秒后再調(diào)用self的run方法
//使用GCD函數(shù)
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
// 2秒后執(zhí)行這里的代碼...
});
//使用NSTimer
[NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:@selector(test) userInfo:nil repeats:NO];
Once代碼,在整個程序運(yùn)行時只執(zhí)行一次
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
// 只執(zhí)行1次的代碼(這里面默認(rèn)是線程安全的)
});
快速迭代代碼
dispatch_apply(10, dispatch_get_global_queue(0, 0), ^(size_t index){
// 執(zhí)行10次代碼,index順序不確定
});
分組隊(duì)列
- 當(dāng)需要對隊(duì)列分組時,而且有先后執(zhí)行順序的需求的時候可以進(jìn)行組
//創(chuàng)建一個組組隊(duì)隊(duì)列
dispatch_group_t group = dispatch_group_create();
//使用組隊(duì)列異步函數(shù),分別有組隊(duì)列,和隊(duì)列的參數(shù).
dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// 執(zhí)行1個耗時的異步操作
});
dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// 執(zhí)行1個耗時的異步操作
});
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
// 等前面的異步操作都執(zhí)行完畢后,回到主線程...
});
IOS中的單例模式
-
單例模式的作用
- 可以保證在程序運(yùn)行過程嗡害,一個類只有一個實(shí)例,而且該實(shí)例易于供外界訪問
- 從而方便地控制了實(shí)例個數(shù)霸妹,并節(jié)約系統(tǒng)資源
-
單例模式的使用場合
- 在整個應(yīng)用程序中,共享一份資源(這份資源只需要創(chuàng)建初始化1次)
單例模式標(biāo)準(zhǔn)化代碼
可以吧指針變?yōu)閕d類型,實(shí)例變量名定義為instance這樣就可以在多處使用了.
#import "Person.h"
@interface Person() <NSCopying>
@end
@implementation Person
//聲明一個全局變量指針,代表唯一的實(shí)例
static Person *_person;
//重寫alloc中實(shí)際起作用的部分,allocWihtZone,所以從始至終就只有一份存儲空間.
+ (instancetype)allocWithZone:(struct _NSZone *)zone
{
//在程序整個生命過程中只運(yùn)行一次的代碼
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_person = [super allocWithZone:zone];
});
return _person;
}
//生成一個完整的對象
+ (instancetype)shareWihtPerson
{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_person = [[Person alloc] init];
});
return _person;
}
//防止使用copy拷貝出新的對象
- (id)copyWithZone:(NSZone *)zone
{
return _person;
}
@end