因?yàn)樽罱?jīng)常遇到許多網(wǎng)絡(luò)請(qǐng)求,需要滿足一個(gè)條件,之后才能繼續(xù)請(qǐng)求
在此舉例:
{
登錄中使用token
這個(gè)token,要作為后續(xù)某些網(wǎng)絡(luò)請(qǐng)求的關(guān)鍵,而token也存在過期的問題,所以請(qǐng)求接口返回過期后,要重新請(qǐng)求token,再執(zhí)行網(wǎng)絡(luò)請(qǐng)求
!:傳統(tǒng)寫法
//1:GCD信號(hào)量控制
typealias NETBLock = ((Bool)->Void)
var semaphore = DispatchSemaphore(value: 1)
func textNET(){
text(id: 1)
DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) {
self.text(id: 2)
}
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
self.text(id: 3)
}
}
func text(id:Int){
DispatchQueue.global().async {[weak self] in
print("??[包含用戶iD請(qǐng)求],開始請(qǐng)求,id\(id)")
self?.semaphore.wait()
print("??[包含用戶iD請(qǐng)求],等待執(zhí)行,id\(id)")
self?.regsiter { isRegsin in
self?.semaphore.signal()
print("??[包含用戶iD請(qǐng)求],結(jié)束等待,id\(id)")
if isRegsin{
self?.load(block: { isSccuess in
if !isSccuess{
self?.semaphore.wait()
self?.login(block: { login in
self?.semaphore.signal()
if login{
self?.text(id: id)
}
})
}
})
}
}
}
}
func regsiter(block:@escaping NETBLock){
if isRegin{
block(true)
return
}
Thread.sleep(forTimeInterval: Double.random(in: 1..<5))
block(true)
isRegin = true
}
func load(block:@escaping NETBLock){
Thread.sleep(forTimeInterval: Double.random(in: 1..<5))
block(Bool.random())
}
func login(block:@escaping NETBLock){
Thread.sleep(forTimeInterval: Double.random(in: 1..<5))
block(true)
}
//2:Operation
//用的不多,忽略了
}
上面的GCD寫法可以說是傳統(tǒng)寫法了.我這里要先注冊(cè),再執(zhí)行下一步,但是預(yù)防并發(fā)注冊(cè),所以這種寫法,有更優(yōu)化方法歡迎提出
接下來說到新語法
enum NetError : Error {
case netfail
}
func login() async throws -> Bool {
let isNet = Bool.random()
if isNet {
// 模擬網(wǎng)絡(luò)延遲
try await Task.sleep(nanoseconds: UInt64.random(in: 1_000_000_000..<5_000_000_000))
return true
} else {
// 拋出網(wǎng)絡(luò)錯(cuò)誤
throw NetError.netfail
}
}
func regsin()async ->Bool{
// 模擬網(wǎng)絡(luò)延遲
do{
try await Task.sleep(nanoseconds: UInt64.random(in: 1_000_000_000..<5_000_000_000))
return true
}catch{
return false
}
}
func loadApi()async->Bool{
// 模擬網(wǎng)絡(luò)延遲
do{
try await Task.sleep(nanoseconds: UInt64.random(in: 1_000_000_000..<5_000_000_000))
return true
}catch{
return false
}
}
func load(){
Task {
let isRegin = await regsin()
//注冊(cè)成功
if isRegin{
let apiResult = await loadApi()
//如果api請(qǐng)求失敗
if !apiResult{
//重新調(diào)用登錄接口,調(diào)用成功后,重新請(qǐng)求
if let loginResult = try? await login(){
load()
}
}
}
}
}
用Task可以處理某些必須串行隊(duì)列,和多個(gè)異步block嵌套的問題,更加簡(jiǎn)介
這里介紹異步block 和 async 搭配用法
func asyncBlock(block:@escaping ((Bool)->Void)){
Thread.sleep(forTimeInterval: Double.random(in: 1..<5))
block(true)
}
func loadData()async -> Bool{
return await withCheckedContinuation { continuation in
asyncBlock { result in
continuation.resume(returning: result)
}
}
}
//返回當(dāng)前線程
func getData()->Task<Void, Error>{
let task = Task {
//檢查當(dāng)前線程是否被取消
try Task.checkCancellation()
let result = await loadData()
}
return task
}
//取消線程示例
func cancelGetData(){
let task = getData()
//取消線程
task.cancel()
}
//對(duì)于這個(gè)語法我更喜歡的一點(diǎn)是,一個(gè)數(shù)組需要遍歷,進(jìn)行異步操作
///假設(shè)我需要用當(dāng)前index 和 index - 1 的數(shù)據(jù)進(jìn)行異步數(shù)據(jù)比對(duì),最后遍歷完成將所有數(shù)據(jù)匯總
傳統(tǒng)方法:只有用信號(hào)量加線程組的方式,較難把控邏輯是否完整,和并發(fā)數(shù)量整體控制
如果用task 可以更加清晰的完成這個(gè)邏輯
上述的方法包含我對(duì)task 和 async,await 理解. 在swiftUI中新的異步語法會(huì)更加附和語言特性.如有不足或者錯(cuò)誤,請(qǐng)及時(shí)幫我指出.謝謝閱讀到此處