ios的多線程一般有NSOperation和GCD.
NSOperation基本使用:
NSBlockOperation * operation1 = [NSBlockOperation blockOperationWithBlock:^{
//任務(wù)A
}];
NSBlockOperation * operation2 = [NSBlockOperation blockOperationWithBlock:^{
//任務(wù)B
}];
NSBlockOperation * operation3 = [NSBlockOperation blockOperationWithBlock:^{
//任務(wù)C
}];
[operation2 addDependency:operation1];//添加依賴
NSOperationQueue * queue = [[NSOperationQueue alloc]init];
[queue addOperations:@[operation1,operation2,operation3] waitUntilFinished:NO];
GCD基本使用:
dispatch_queue_t queue = dispatch_queue_create("gcd_queue", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(queue, ^{
// 任務(wù)D
}
});
barrier:
dispatch_barrier_async(queue, ^{
// 任務(wù)E
//E會等待D完成后執(zhí)行,且E完成后才會執(zhí)行F哑蔫。其中barrier的queue是create才有這個作用,如果是全局隊列作用與dispatch_async一樣撩笆。
}
});
dispatch_async(queue, ^{
// 任務(wù)F
}
});
信號量
//創(chuàng)建信號量并設(shè)置計數(shù)默認為0
dispatch_semaphore_t sema = dispatch_semaphore_create(0);
//若計數(shù)為0則一直等待烫饼,當前線程阻塞起趾,信號量減一
dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
//與wait配對使用唉锌,阻塞的線程會繼續(xù)執(zhí)行隅肥,信號量加一
dispatch_semaphore_signal(sema);
調(diào)度組
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_group_t group = dispatch_group_create();
dispatch_group_async(group, queue, ^{
//任務(wù)1
});
dispatch_group_enter(_group);
dispatch_group_leave(_group);//成對出現(xiàn)添加、移除標記
dispatch_group_notify(group, queue, ^{
//等待任務(wù)都執(zhí)行完后的監(jiān)聽袄简。
});
簡單的多線程都很好理解腥放。當實際開發(fā)中使用AFN框架時候,因為框架內(nèi)部網(wǎng)絡(luò)請求會自動實現(xiàn)多線程绿语,所以在使用時候難免會產(chǎn)生麻煩捉片。有時候會出現(xiàn)一個頁面多個網(wǎng)絡(luò)請求,有依賴關(guān)系或無依賴關(guān)系汞舱。下載功能的app,有可能遇到先并發(fā)執(zhí)行幾個任務(wù)宗雇,再執(zhí)行一個任務(wù)昂芜,之后再并發(fā)執(zhí)行幾個任務(wù)。下面就個人理解寫出解決方案赔蒲,當然不唯一泌神,但可以實現(xiàn)。
一舞虱、異步執(zhí)行A任務(wù)欢际,執(zhí)行后異步執(zhí)行B任務(wù),然后執(zhí)行C任務(wù)刷新UI矾兜。
解決:先利用NSOperation設(shè)置依賴關(guān)系损趋。保證執(zhí)行順序,因為NSOperation默認并發(fā)開辟了線程椅寺,AFN又開辟線程浑槽,所以可以利用信號量阻塞線程達到效果。
__weak typeof (self)weakSelf =self;
NSBlockOperation * operation1 = [NSBlockOperation blockOperationWithBlock:^{
[weakSelf requestA];
}];
NSBlockOperation * operation2 = [NSBlockOperation blockOperationWithBlock:^{
[weakSelf requestB];
}];
NSBlockOperation * operation3 = [NSBlockOperation blockOperationWithBlock:^{
[weakSelf requestC];
}];
[operation2 addDependency:operation1];
[operation3 addDependency:operation2];
//保證執(zhí)行順序返帕。
NSOperationQueue * queue = [[NSOperationQueue alloc]init];
[queue addOperations:@[operation1,operation2,operation3] waitUntilFinished:NO];
-(void)requestA{
//創(chuàng)建信號量并設(shè)置計數(shù)默認為0
dispatch_semaphore_t sema = dispatch_semaphore_create(0);
[AFNmanager GET:@"" parameters:nil progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
dispatch_semaphore_signal(sema);
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
//計數(shù)+1操作
dispatch_semaphore_signal(sema);
}];
dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
}
requestB與requestA類似桐玻。因為依賴關(guān)系保證了執(zhí)行順序,AFN開辟新線程后荆萤,調(diào)用了wait函數(shù)镊靴,阻塞了requestA的線程,導(dǎo)致B任務(wù)無法開啟,然而AFN開辟的線程還可以繼續(xù)執(zhí)行偏竟。請求結(jié)束后回調(diào)煮落,signal函數(shù)使requestA所在線程不再阻塞。轉(zhuǎn)向B任務(wù)線程苫耸。以此類推州邢,執(zhí)行到C,C直接主線程刷新UI褪子。
-(void)requestC{
dispatch_async(dispatch_get_main_queue(), ^{
//更新UI操作
});
}
二量淌、異步無序執(zhí)行A、B任務(wù)后執(zhí)行C任務(wù)刷新UI嫌褪。(兩種思路呀枢,還有更多不再列舉)
1.調(diào)度組實現(xiàn)
_group = dispatch_group_create();
[self loadA];
[self loadB];
dispatch_group_notify(_group, dispatch_get_main_queue(), ^{
[self reloadUI];
});
- (void) loadA {//loadB與loadA相似
dispatch_group_enter(_group);
[AFNmanager GET:@"" parameters:nil progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
dispatch_group_leave(_group);
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
dispatch_group_leave(_group);
}];
}
2.調(diào)度組異步+信號量實現(xiàn)
- (void) loadData {
// 創(chuàng)建信號量
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
// 創(chuàng)建全局并行
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_group_t group = dispatch_group_create();
dispatch_group_async(group, queue, ^{
//任務(wù)A
[AFNmanager GET:@"" parameters:nil progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
dispatch_semaphore_signal(semaphore);
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
dispatch_semaphore_signal(semaphore);
}];
});
dispatch_group_async(group, queue, ^{
//任務(wù)B
[AFNmanager GET:@"" parameters:nil progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
dispatch_semaphore_signal(semaphore);
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
dispatch_semaphore_signal(semaphore);
}];
});
}
[self loadData];
dispatch_group_notify(group, queue, ^{
// 2個請求對應(yīng)2次信號等待
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
//在這里減2,AB任務(wù)完后信號量加了2笼痛,才可以繼續(xù)執(zhí)行裙秋,只要AB中任何一個沒有執(zhí)行完,就會阻塞在wait這缨伊。
//在這里 進行請求后的方法摘刑,回到主線程
dispatch_async(dispatch_get_main_queue(), ^{
//更新UI操作
});
});
三、多任務(wù)并發(fā)后執(zhí)行一個任務(wù)后繼續(xù)多任務(wù)并發(fā)執(zhí)行刻坊。
dispatch_queue_t queue = dispatch_queue_create("gcd_queue", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(queue, ^{ //任務(wù)1 任務(wù)2枷恕、3等類似于1。
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
[AFNmanager GET:@"" parameters:nil progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
dispatch_semaphore_signal(semaphore);
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
//計數(shù)+1操作
dispatch_semaphore_signal(semaphore);
}];
//阻塞任務(wù)1所在線程谭胚,等待執(zhí)行結(jié)束后不再阻塞
dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
}
});
dispatch_barrier_async(queue, ^{
//前面的并發(fā)任務(wù)執(zhí)行完后執(zhí)行 內(nèi)部類似于任務(wù)1.
}
});
dispatch_async(queue, ^{
// 后面的并發(fā)任務(wù)加不加信號量控制都可以徐块。
}
});