我有一个按钮,通过 segue 将 View Controller 连接到另一个 View Controller ,按下时,将 UITextField
中的 text
作为参数发送到 AFNetwork
POST
请求,并且必须根据请求是否成功来决定segue是否可以继续。
所以我这样写:
var proceed = false
let token = tokenTextField.text.trim()
let requestURL = "https://myapi.com/authenticate/"
// Make this a synchronous HTTP POST request so that we only decide whether
// to proceed with the segue or not once we know if the request was successful
manager.POST(requestURL,
parameters: [ "code" : token ],
success: { (operation: AFHTTPRequestOperation!, responseObject: AnyObject!) in
proceed = true
NSLog("Success! Response is \(responseObject.description)")
},
failure: { (operation: AFHTTPRequestOperation!, error: NSError!) in
println("Failure! Error is: \(error.localizedDescription)")
proceed = false
self.displayLoginAttempErrorAlert()
}).waitUntilFinished()
println("what a hard thing")
return proceed
但这段代码在 success
或 error
回调中打印任何内容之前打印了 "what a hard thing"
,因此它显然是异步的。由于上面解释的原因,我希望它是同步的。我怎样才能强制这种行为?
请记住,请求本身没有任何问题。我只是想确保事物的正确顺序。
更新:我知道强制同步可能会阻塞 UI,这对我来说很好。这就像一个登录屏幕,在发出请求和响应到达之间不应发生任何事情。
提前致谢
请您参考如下方法:
您可以:
- 指定
manager
的completionQueue
为主队列以外的东西(这样当你阻塞主线程等待完成时就不会死锁要调用的处理程序); dispatch_semaphore_semaphore
在开始请求之前;dispatch_semaphore_signal
请求完成 block 内的信号量;和dispatch_semaphore_wait
在请求之后但在您从函数返回之前的信号量。
但在我看来,让异步方法同步运行从根本上说是不正确的方法。它不仅是一个糟糕的用户体验,限制了你的用户界面等,而且你还有让看门狗进程杀死你的应用程序的风险。
与其让异步进程在 shouldPerformSegueWithIdentifier
中同步运行,不如采用标准的异步模式:
- 从 UIKit 控件中删除您可能拥有的现有 segue 到下一个场景;
- 在 View Controller 之间创建一个新的 segue(如 shown here),它不会自动执行,而只会以编程方式执行(见下文);
- 有一个执行异步请求的
IBAction
,并且有一个完成 block - 根据需要以编程方式启动 segue。