问题描述
如何在while循环中使用完成处理程序/调度队列?
我有一个称为getHub()
的方法,它是一个完成处理程序,因为我希望在完成相关值后执行代码。当用户按下按钮时,我称之为:
SetupAPI().getHub(completion: { response,error in
print("testing")
print(response)
print(error)
})
它调用了我的API,如果该API返回了我所期望的错误/值,或者Almofire由于某种原因无法执行该请求,则会在tries
变量中添加一个。允许的最大尝试次数是maxTries
变量给定的3次。如果tries
变量等于maxTries
变量,则将布尔timeout
设置为true
。如果tries
变量低于maxTries
变量,则代码将等待timeoutInSeconds
(这是10秒)的时间,然后退出while循环,这将再次运行代码。 / p>
类似地,如果从我的API中获取数据后返回了正确的值,则将found
设置为true
。
如果这些变量之一为true,则while循环中断。并将错误发送回上述代码的完成处理程序(然后,我可以告诉用户某些地方出了问题)。
但是,当我运行它时,上面的完成处理程序还没有完成,并且代码只运行了while循环,并在控制台填充starting
和fetching
时一遍又一遍地调用了函数。通过我的两个打印语句在下面的代码中进行调试。有什么问题,在这种情况下可以使用dispatchQueue /完成处理程序吗?
func getHub(completion: @escaping (Bool,Error?) -> Void) {
var tries = 0
let maxTries = 3
let timeoutInSeconds = 10.0
var found = false
var timeout = false
while !found || !timeout{
print("starting")
getHubCallAPI(completion: {status,error in
if(error == nil){
print(status)
if (status == "No documents found"){
if(tries >= maxTries){
print("Tired too many times")
timeout = true
return completion(false,nil)
}
tries += 1
dispatchQueue.main.asyncAfter(deadline: .Now() + timeoutInSeconds){
return
}
}else{
found = true
print("Hub found")
return completion(true,nil)
}
}else{
print("error")
return completion(false,error)
}
})
}
}
func getHubCallAPI(completion: @escaping (String,Error?) -> Void) {
print("fetching")
AF.request("https://discovery.ellisn.com",encoding: URLEncoding.default).response { response in
print("Request: \(response.request)")
print("Response: \(response.response)")
print("Error: \(response.error)")
if(response.error != nil){
return completion("",response.error)
}
if let data = response.data,let status = String(data: data,encoding: .utf8) {
return completion(status,nil)
}
}
}
任何问题,或者需要进一步澄清,然后问。谢谢。
解决方法
您可以尝试以下操作:
func getHub(triesLeft: Int = 3,completion: @escaping (Bool,Error?) -> Void) {
let timeoutInSeconds = 1.0
print("starting")
getHubCallAPI(completion: { status,error in
if error == nil {
print(status)
if status != "No documents found" {
print("Hub found")
return completion(true,nil)
}
} else {
print("error")
return completion(false,error) // comment out if the loop should continue on error
}
if triesLeft <= 1 {
print("Tried too many times")
return completion(false,nil)
}
DispatchQueue.main.asyncAfter(deadline: .now() + timeoutInSeconds) {
getHub(triesLeft: triesLeft - 1,completion: completion)
}
})
}
就这样叫一次:
getHub(triesLeft: 2,completion: { ... })
请注意,除非出于其他原因需要,否则无需返回(Bool,Error?)
。第二个参数始终为nil
-您可能希望传播错误。从理论上讲,您可以返回(String?,Error?)
。