使用信號(hào)量(dispatch_semaphore_t
)來(lái)實(shí)現(xiàn),AFN回調(diào)執(zhí)行完成之后再執(zhí)行后面的代碼
什么是信號(hào)量?
- 為了防止出現(xiàn)因多個(gè)程序同時(shí)訪問(wèn)一個(gè)共享資源而引發(fā)的一系列問(wèn)題,我們需要一種方法,它可以通過(guò)生成并使用令牌來(lái)授權(quán),在任一時(shí)刻只能有一個(gè)執(zhí)行線程訪問(wèn)代碼的臨界區(qū)域.臨界區(qū)域是指執(zhí)行數(shù)據(jù)更新的代碼需要獨(dú)占式地執(zhí)行.而信號(hào)量就可以提供這樣的一種訪問(wèn)機(jī)制,讓一個(gè)臨界區(qū)同一時(shí)間只有一個(gè)線程在訪問(wèn)它,也就是說(shuō)信號(hào)量是用來(lái)調(diào)協(xié)進(jìn)程對(duì)共享資源的訪問(wèn)的.
- 信號(hào)量就是一個(gè)資源計(jì)數(shù)器,對(duì)信號(hào)量有兩個(gè)操作來(lái)達(dá)到互斥,分別是P和V操作.一般情況是這樣進(jìn)行臨界訪問(wèn)或互斥訪問(wèn)的:設(shè)信號(hào)量值為1,當(dāng)一個(gè)進(jìn)程1運(yùn)行是,使用資源,進(jìn)行P操作,即對(duì)信號(hào)量值減1,也就是資源數(shù)少了1個(gè).這是信號(hào)量值為0.系統(tǒng)中規(guī)定當(dāng)信號(hào)量值為0是,必須等待,知道信號(hào)量值不為零才能繼續(xù)操作.這時(shí)如果進(jìn)程2想要運(yùn)行,那么也必須進(jìn)行P操作,但是此時(shí)信號(hào)量為0,所以無(wú)法減1,即不能P操作,也就阻塞.這樣就到到了進(jìn)程1排他訪問(wèn).當(dāng)進(jìn)程1運(yùn)行結(jié)束后,釋放資源,進(jìn)行V操作.資源數(shù)重新加1,這是信號(hào)量的值變?yōu)?,這時(shí)進(jìn)程2發(fā)現(xiàn)資源數(shù)不為0,信號(hào)量能進(jìn)行P操作了,立即執(zhí)行P操作.信號(hào)量值又變?yōu)?,次數(shù)進(jìn)程2咱有資源,排他訪問(wèn)資源,這就是信號(hào)量來(lái)控制互斥的原理.
- 在iOS開(kāi)發(fā)中,我們可以通過(guò)
dispatch
方法來(lái)設(shè)置信號(hào)量,實(shí)現(xiàn)某些需求.
在當(dāng)前項(xiàng)目中,我需要實(shí)現(xiàn)一個(gè)功能,那就是發(fā)送請(qǐng)求之前判斷token是否過(guò)期了,如果過(guò)期,那么需要刷新token,然后再發(fā)送請(qǐng)求.那么我必須保證發(fā)送請(qǐng)求之前,token必須刷新完成,即刷新token的請(qǐng)求的回調(diào)必須執(zhí)行完之后才能執(zhí)行發(fā)送請(qǐng)求的代碼.
//刷新token
- (void)reloadToken
{
NSLog(@"1");
NSLog(@"%@",[NSThread currentThread]);
//先創(chuàng)建一個(gè)semaphore
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
//拼接路徑
NSString *url=[NSString stringWithFormat:@"%@%@%@",BASE_URL,TOKEN_REFRESH_URL,[LTools cacheForKey:User_id]];
AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
//為請(qǐng)求的回調(diào)開(kāi)啟線程,不然會(huì)形成死鎖,代碼永遠(yuǎn)都不會(huì)執(zhí)行了
manager.completionQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
//添加token到請(qǐng)求頭
[manager.requestSerializer setValue:[LTools cacheForKey:TokenNew] forHTTPHeaderField:@"oldToken"];
//發(fā)送請(qǐng)求
[manager GET:url parameters:nil success:^(NSURLSessionDataTask * _Nonnull task, id _Nonnull responseObject)
{
//存儲(chǔ)新的token
NSString *newToken = responseObject[@"data"][@"token"];
[LTools cache:newToken ForKey:TokenNew];
NSLog(@"3-1");
NSLog(@"3-1%@",[NSThread currentThread]);
//發(fā)出已完成的信號(hào)
dispatch_semaphore_signal(semaphore);
}
failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error)
{
//如果請(qǐng)求失敗,那么取消登錄狀態(tài),刪除個(gè)人數(shù)據(jù)
[LTools storage:NO ForKey:LoginState];
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
//刪除所有用戶數(shù)據(jù)
[userDefaults removeObjectForKey:User_id];
[userDefaults removeObjectForKey:User_headimg];
[userDefaults removeObjectForKey:User_mobile];
[userDefaults removeObjectForKey:User_nickName];
[userDefaults removeObjectForKey:User_isPayPassword];
[userDefaults removeObjectForKey:User_CarId];
[userDefaults removeObjectForKey:User_CarLogo];
[userDefaults removeObjectForKey:User_isWeChat];
[userDefaults removeObjectForKey:User_isQQ];
[userDefaults removeObjectForKey:TokenNew];
[userDefaults removeObjectForKey:User_gender];
[userDefaults removeObjectForKey:User_carBrand];
[userDefaults removeObjectForKey:User_RecommendCode];
NSLog(@"3-2");
NSLog(@"3-2%@",[NSThread currentThread]);
//發(fā)出已完成的信號(hào)
dispatch_semaphore_signal(semaphore);
}];
NSLog(@"2");
NSLog(@"%@",[NSThread currentThread]);
//等待執(zhí)行趁怔,不會(huì)占用資源
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
}
最后編輯于 :
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者