什么是線程褥影?什么是主線程池户?什么是子線程?
在我們程序運(yùn)行期間,每個(gè)正在運(yùn)行的代碼段校焦,被稱為線程赊抖。
程序運(yùn)行期間,至少有一個(gè)線程寨典,該線程為主線程氛雪,主要負(fù)責(zé)刷新UI,比如添加控件耸成,刪除控件报亩,更新控件等。
如果遇到耗時(shí)的功能井氢,程序中有多個(gè)線程捆昏,除了主線程,其余的都是子線程毙沾。
子線程主要負(fù)責(zé)骗卜,耗時(shí)的任務(wù),比如左胞,網(wǎng)絡(luò)請(qǐng)求寇仓,處理大數(shù)據(jù)等。
iOS 如果遇到多個(gè)耗時(shí)的任務(wù)烤宙,或者要求遍烦,多個(gè)任務(wù)同時(shí)執(zhí)行。我們可以使用多線程編程技術(shù)躺枕,開(kāi)辟多個(gè)線程服猪,把任務(wù)放到其他進(jìn)程中執(zhí)行。
線程與線程之間獨(dú)立執(zhí)行拐云,互不干擾罢猪。
//iOS 中多線程方式
一,NSTread ? 線程類
? 1叉瘩,使用線程類膳帕,來(lái)開(kāi)辟線程
?二,NSobject分類方法
?使用場(chǎng)景:只想要一個(gè)操作薇缅,在開(kāi)辟的子線程中執(zhí)行危彩。
[self performSelectorInBackground:@selector(printString;) ?withObject:@"分類開(kāi)辟子線程方法"];
[self performSelectorInBackground:@selector(printString;)? withObject:@"分類開(kāi)辟子線程方法1"];
[self performSelectorInBackground:@selector(printString;)? withObject:@"分類開(kāi)辟子線程方法2"];
[self performSelectorInBackground:@selector(printString;)? withObject:@"分類開(kāi)辟子線程方法3"];
// 在主線程中執(zhí)行SEL方法,傳遞參數(shù)泳桦,方法執(zhí)行結(jié)束之前是否等待 ? ?yes 等待 ?汤徽,no不等待
// @"111"是作為參數(shù)傳遞進(jìn) 方法printString:?
[self performSelectorOnMainThread:@selector(printString:) withObject:@"111" waitUntilDone:YES];
主線程主要用來(lái)接受用戶相應(yīng)的操作,更新UI灸撰,因此谒府,我們添加UI漆羔,更新UI,以及刪除UI的操作狱掂,一定要放在主線程中執(zhí)行演痒。比如:label.text = @"aaa";
// 四 , GCD
GCD屬于函數(shù)級(jí)別的多線程趋惨,主要是分配不同功能的隊(duì)列鸟顺,提供給用戶使用。
因此器虾,我們?cè)谑褂肎CD時(shí)讯嫂,根據(jù)需求,選用不同功能的隊(duì)列解決問(wèn)題兆沙。
//1. gcd 串行隊(duì)列
- (IBAction)serialQueue:(id)sender
{
// ?何時(shí)使用: 當(dāng)多個(gè)任務(wù)具有依賴關(guān)系的時(shí)候欧芽。
// 比如:處理用戶輸入-》網(wǎng)絡(luò)請(qǐng)求-》處理請(qǐng)求結(jié)果 -》登錄
//1.創(chuàng)建一個(gè)串行隊(duì)列
dispatch_queue_t queue = dispatch_queue_create("queue",DISPATCH_QUEUE_SERIAL);
//2.添加任務(wù),任務(wù)只能是block或者是函數(shù)類型
// 兩個(gè)參數(shù)葛圃,前面一個(gè)是隊(duì)列名千扔,后面是添加的任務(wù),代碼塊block
dispatch_async(queue,^{
NSLog(@"%@",[NSThread currentThread];
NSLog(@"I was borned");
});
dispatch_async(queue,^{
NSLog(@"%@",[NSThread currentThread];
NSLog(@"i growed");
});
dispatch_async(queue,^{
NSLog(@"%@",[NSThread currentThread];
NSLog(@"I married");
});
dispatch_async(queue,^{
NSLog(@"%@",[NSThread currentThread];
NSLog(@"You were dead");
});
// 2.全局串行隊(duì)列是main函數(shù)執(zhí)行所在的主線程的隊(duì)列库正,我們稱為主隊(duì)列曲楚。主隊(duì)列是一個(gè)全局串行隊(duì)列,便于用戶訪問(wèn)
// 獲取主隊(duì)列
dispatch_queue_t mainQueue = dispatch_get_main_queue();
// 給主隊(duì)列添加刷新UI的操作
dispatch_async(mainQueue,^{
self.view.backgroundColor = [UIColor redColor];
});
}
// 并行隊(duì)列 ?conCurrentQueue
- (IBAction)conCurrentQueue:(id)sender
{
// 并行隊(duì)列是一種同時(shí)可以有多個(gè)任務(wù)并發(fā)執(zhí)行的隊(duì)列
// 使用方式:當(dāng)多個(gè)任務(wù)褥符,沒(méi)有依賴關(guān)系龙誊,誰(shuí)先執(zhí)行,誰(shuí)后執(zhí)行喷楣,都不重要趟大。
//1. 創(chuàng)建并行隊(duì)列
dispatch_queue_t currentQueue = dispatch_queue_create("queue",DISPATCH_QUEUE_CONCURRENT);
// 2.提交操作
dispatch_async(currentQueue,^{
NSLog(@"%@",[NSThread currentThread]);
NSLog(@"猴子一 連入游戲");
}
dispatch_async(currentQueue,^{
// block 塊內(nèi)封裝的可以是需要執(zhí)行的任務(wù)
NSLog(@"%@",[NSThread currentThread]);
NSLog(@"猴子二 連入游戲");
}
dispatch_async(currentQueue,^{
// block 塊內(nèi)封裝的可以是需要執(zhí)行的任務(wù)
NSLog(@"%@",[NSThread currentThread]);
NSLog(@"猴子三 連入游戲");
}
}
// 組提交方式
- (IBAction)group:(id)sender
{
// 什么是組提交方式
// 某些時(shí)候,我們需要把一些操作铣焊,歸為一類操作逊朽,比如,鏈接操作粗截,讀取操作惋耙。而鏈接操作和讀取操作中捣炬,又有多個(gè)操作熊昌。此時(shí)使用組提交方式。
//1湿酸、創(chuàng)建一個(gè)并行隊(duì)列
dispatch_queue_t queue1 = dispatch_queue_create("queue1", DISPATCH_QUEUE_CONCURRENT);
//2婿屹、創(chuàng)建一個(gè)組隊(duì)列
dispatch_group_t group1 = dispatch_group_create();
//3、提交
dispatch_group_async(group1, queue1, ^{
NSLog(@"玩家1連入游戲");
});
dispatch_group_async(group1, queue1, ^{
NSLog(@"玩家2連入游戲");
});
dispatch_group_async(group1, queue1, ^{
NSLog(@"玩家3連入游戲");
});
dispatch_group_async(group1, queue1, ^{
NSLog(@"玩家4連入游戲");
});
dispatch_group_async(group1, queue1, ^{
NSLog(@"玩家5連入游戲");
});
// 組中通知提交方式推溃,當(dāng)組中所有其他操作執(zhí)行完畢后昂利,它才會(huì)執(zhí)行
dispatch_group_notify(group1,queue1,^{
NSLog(@"所有玩家接入完畢,游戲開(kāi)始");
});
}
// barrier 障礙提交方式
- (IBAction)barrier:(id)sender
{
// barrier 提交方式,其實(shí)是把多個(gè)操作蜂奸,劃分為兩個(gè)部分犁苏,這兩個(gè)部分執(zhí)行方式都是并發(fā)執(zhí)行的。
// ?只要多一個(gè)barrier 就會(huì)劃分出來(lái)兩個(gè)部分
// ?通常用于前面有多個(gè)操作扩所,后面有多個(gè)操作围详,后面部分要等到前面部分執(zhí)行完畢再執(zhí)行
//1. 并行執(zhí)行
dispatch_queue_t queue = dispatch_queue_create("queue",DISPATCH_QUEUE_CONCURRENT);
//2.提交操作
dispatch_async(queue,^{
NSLog(@"網(wǎng)絡(luò)連接成功");
});
dispatch_async(queue,^{
NSLog(@"用戶請(qǐng)求成功“);
});
dispatch_async(queue,^{
NSLog(@"驗(yàn)證用戶名密碼");
});
// 障礙提交方式
dispatch_barrier_async(queue,^{
NSLog(@"驗(yàn)證完成");
});
dispatch_async(queue,^{
NSLog(@"讀取用戶數(shù)據(jù)");
});
}
// after 延遲執(zhí)行
- (IBAction)after:(id)after{
// 延遲執(zhí)行,多用于加載圖祖屏,線程睡眠等使用場(chǎng)景
// 1.從哪個(gè)時(shí)間點(diǎn)去
// 2. 過(guò)幾秒后
// 3.提交到哪個(gè)隊(duì)列中
// 4. 執(zhí)行block
dispatch_after(dispatch_time(DISPATCH_TIME_NOW,(int64_t)(5*NSEC_PER_SEC)) , dispatch_get_main_queue(),^{
self.view.backgroundColor = [UIColor redColor];
// 延遲五秒助赞,把當(dāng)前控制器所在的視圖的背景顏色換為紅色
}); ??
}
// apply 重復(fù)提交執(zhí)行
- (IBAction)apply:(id)sender
{
// 使用場(chǎng)景:有多個(gè)任務(wù),需要提交到隊(duì)列中時(shí)袁勺,使用apply方式
//1. 把多個(gè)任務(wù)存儲(chǔ)到數(shù)組中
NSArray *array = @[@"圖片1",@"圖片2",@"圖片3",@"圖片4",@"圖片5"];
//2. 提交到一個(gè)并行隊(duì)列中
// 參數(shù)1. 數(shù)組個(gè)數(shù)雹食,重復(fù)執(zhí)行次數(shù)
// 參數(shù)2.提交到哪個(gè)隊(duì)列中
// 參數(shù)3.當(dāng)前執(zhí)行的次數(shù)
dispatch_apply(5,dispatch_get_global_queue(0,0),^(size_t i){
// i從0開(kāi)始到 5-1
NSLog(@"%@",array[i]);
});
}
// NSOperationQueue?
- (IBAction)operationQueue:(id)sender
{
// 使用場(chǎng)景,當(dāng)我們有多個(gè)任務(wù),都需要放倒子線程中執(zhí)行時(shí)期丰,使用操作隊(duì)列這種方式群叶,更為高效,隊(duì)列內(nèi)部給我們創(chuàng)建了合適的線程數(shù)钝荡。
// ?什么是操作隊(duì)列盖呼? 何時(shí)使用操作隊(duì)列?
// 操作隊(duì)列事以一個(gè)隊(duì)列化撕,內(nèi)部提交的是操作對(duì)象几晤,隊(duì)列中可以給我們開(kāi)辟適當(dāng)?shù)木€程數(shù)去解決多個(gè)要執(zhí)行的操作
// 操作隊(duì)列是以合適的線程數(shù),更加高效地解決需求
// 創(chuàng)建操作對(duì)象
NSInvocationOperation *invo1 = [[NSInvovationOperation alloc] initWithTarget:self selector:@selector(printString:) object:@"1111"];
NSInvocationOperation *invo2 = [[NSInvovationOperation alloc] initWithTarget:self selector:@selector(printString:) object:@"2222"];
NSInvocationOperation *invo3 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(printString:) object:@"333"];
// 2.以block方式創(chuàng)建對(duì)象
NSBlockOperation *bo1 = [NSBlockOperation blockOperationWithBlock:^{
// block 內(nèi)部填寫我們要執(zhí)行的操作植阴,當(dāng)該操作對(duì)象執(zhí)行時(shí)蟹瘾,會(huì)調(diào)用block,執(zhí)行操作
NSLog(@"I");
}];
NSBlockOperation *bo2 = [NSBlockOperation blockOperationWithBlock:^{
// block 內(nèi)部填寫我們要執(zhí)行的操作掠手,當(dāng)該操作對(duì)象執(zhí)行時(shí)憾朴,會(huì)調(diào)用block,執(zhí)行操作
NSLog(@"lOVE");
}];
NSBlockOperation *bo3 = [NSBlockOperation blockOperationWithBlock:^{
//block 內(nèi)部填寫我們要執(zhí)行的操作喷鸽,當(dāng)該操作對(duì)象執(zhí)行時(shí)众雷,會(huì)調(diào)用block,執(zhí)行操作
NSLog(@"You");
}];
// 1. 創(chuàng)建一個(gè)操作隊(duì)列
NSOperationQueue *queue1 = [[NSOperationQueue alloc] init];
// 設(shè)置操作隊(duì)列的最大并發(fā)數(shù)
queue1.maxConcurrentOperationCount = 3;
// 同一時(shí)間點(diǎn)做祝,能夠執(zhí)行的操作數(shù)
// 當(dāng)隊(duì)列的最大并發(fā)數(shù)為1時(shí)為砾省,串行隊(duì)列,大于1為并行隊(duì)列混槐。
// 如何讓并行隊(duì)列中编兄,某些任務(wù)按照順序執(zhí)行?
// ?給任務(wù)添加依賴關(guān)系
[invo2 addDependency:invo1];
[invo3 addDependency:invoke];
//把操作添加到操作隊(duì)列里面
//? ? [queue1 addOperation:invo1];
//? ? [queue1 addOperation:invo2];
//? ? [queue1 addOperation:invo3];
//把操作添加到操作隊(duì)列里面
[queue1 addOperation:bo1];
[queue1 addOperation:bo2];
[queue1 addOperation:bo3];
}
- (IBAction)block:(id)sender {
//? [self printNumber];
[NSThread detachNewThreadSelector:@selector(printNumber) ?toTarget:self withObject:nil];
}
- (IBAction)thread:(id)sender {
//1声登、開(kāi)辟一個(gè)線程
// [NSThread detachNewThreadSelector:@selector(printNumber) toTarget:self withObject:nil];
// 注意: detach 創(chuàng)建的線程狠鸳,自動(dòng)執(zhí)行揣苏,通常用于默認(rèn)執(zhí)行的操作。
// 2件舵、NSThread 開(kāi)辟的線程另一種方法? init
NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(printString:) object:@"111" ];
//初始化方法創(chuàng)建的線程卸察,需要我們手動(dòng)開(kāi)啟,使用start方法
[thread start];
//結(jié)束線程
// [thread cancel];
NSLog(@"%@ %ld",[NSThread currentThread],[NSThread isMainThread]);
}
// 打印一個(gè)string
- (void)printString:(NSString *)string
{
NSLog(@"%@ %d %@",[NSThread currentThread ],[NSThread isMainThread],string);
}
- (IBAction)cankao:(id)sender {
NSLog(@"aaaaa");
}
//for 循環(huán)方法
- (void)printNumber
{
@autoreleasepool {
for (int i = 0; i < 655000000; i++) {
NSLog(@"%d",i);
}
}
}
- (IBAction)sync:(id)sender {
//同步提交方式會(huì)等 提交的操作執(zhí)行完畢后铅祸,再執(zhí)行后面的操作蛾派。
//同步提交方式會(huì)卡主線程。
dispatch_sync(dispatch_get_global_queue(0, 0), ^{
NSLog(@"%@",[NSThread currentThread]);
for (int i = 0; i < 10; i ++) {
NSLog(@"%d",i);
}
});
NSLog(@"%@",[NSThread currentThread]);
NSLog(@"我在下面我在下面我在下面");
dispatch_sync(dispatch_get_global_queue(0, 0), ^{
NSLog(@"aaaaaaaaa");
});
}
void sum(void *string)
{
//注意傳遞過(guò)來(lái)的是什么類型就用什么類型打印个少。
NSLog(@"%s",string);
}
// 提交函數(shù)
- (IBAction)function:(id)sender {
dispatch_async_f(dispatch_get_main_queue(), "aaa", sum);
//獲取線程名
dispatch_queue_t queue = dispatch_queue_create("aaa", DISPATCH_QUEUE_CONCURRENT);
const char *name = dispatch_queue_get_label(queue);
NSLog(@"%@",[NSString stringWithUTF8String:(const char *)name]);
}