Timeout
塊中的代碼將永遠不會運行,因爲定時器將在主線程上觸發,但您使用while
循環阻塞主線程。
你在這裏還有一個問題,你打電話給Server.checkUsername(username!)
並返回結果,這表明這必須是一個同步調用(這是不好的)。所以,這也可能阻止那裏的主線程。它甚至不會嘗試啓動Timeout
邏輯,直到checkUsername
返回。
有這方面的修復,但在我看來,這要求一個非常不同的模式。一個人不應該編寫具有輪詢一些完成狀態的空轉循環的代碼。與completionHandler
關閉採用異步模式要好得多。但沒有關於什麼checkUsername
正在做的更多信息,很難得到更具體的。
但是,理想情況下,如果你的checkUsername
正在建設一個NSMutableURLRequest
,只需指定timeoutInterval
爲,然後與的NSURLErrorDomain
domain
爲NSError
的NSURLSessionTask
完成塊校驗和的NSURLError.TimedOut
代碼。如果它已經在運行,您可能還想取消先前的請求。
func startRequestForUsername(username: String, timeout: NSTimeInterval, completionHandler: (Bool?, NSError?) ->()) -> NSURLSessionTask {
let request = NSMutableURLRequest(URL: ...) // configure your request however appropriate for your web service
request.timeoutInterval = timeout // but make sure to specify timeout
let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, response, error in
dispatch_async(dispatch_get_main_queue()) {
guard data != nil && error == nil else {
completionHandler(nil, error)
return
}
let usernameAvailable = ... // parse the boolean success/failure out of the `data` however appropriate
completionHandler(usernameAvailable, nil)
}
}
task.resume()
return task
}
然後你可以使用它像這樣:
private weak var previousTask: NSURLSessionTask?
func checkUsername(username: String) {
// update the UI to say that we're checking the availability of the user name here, e.g.
usernameStatus.text = "Checking username availability..."
// now, cancel prior request (if any)
previousTask?.cancel()
// start new request
let task = startRequestForUsername(username, timeout: 5) { usernameAvailable, error in
guard usernameAvailable != nil && error == nil else {
if error?.domain == NSURLErrorDomain && error?.code == NSURLError.TimedOut.rawValue {
// everything is cool, the task just timed out
} else if error?.domain == NSURLErrorDomain && error?.code != NSURLError.Cancelled.rawValue {
// again, everything is cool, the task was cancelled
} else {
// some error other happened, so handle that as you see fit
// but the key issue that if it was `.TimedOut` or `.Cancelled`, then don't do anything
}
return
}
if usernameAvailable! {
// update UI to say that the username is available
self.usernameStatus.text = "Username is available"
} else {
// update UI to say that the username is not available
self.usernameStatus.text = "Username is NOT available"
}
}
// save reference to this task
previousTask = task
}
順便說一句,如果你做這樣的請求優美,異步處理的,還可以增加超時間隔(例如可能10或15秒)。我們並不凍結用戶界面,所以我們可以做我們想做的任何事情,而不是人爲限制請求所允許的時間。
來源
2015-10-17 22:50:52
Rob
你應該描述'checkUsername'是如何實現的。這段代碼的重構從那裏開始。 – Rob