我正在开发一个计算东西的应用程序。
用户将在OperationViewController
中输入输入,然后单击“计算”。计算结果后,执行segue以显示ResultsViewController
。
有些计算需要很长时间,所以我认为应该在后台线程中完成。我应该显示一条消息,说明它正在计算,并且是一个活动指示器。
我还从某个地方获取了一些代码,使得在后台做事情变得超级快速。代码如下:
import Foundation
infix operator ~> {}
/**
Executes the lefthand closure on a background thread and,
upon completion, the righthand closure on the main thread.
Passes the background closure's output, if any, to the main closure.
*/
func ~> <R> (
backgroundClosure: () -> R,
mainClosure: (result: R) -> ())
{
dispatch_async(queue) {
let result = backgroundClosure()
dispatch_async(dispatch_get_main_queue(), {
mainClosure(result: result)
})
}
}
/** Serial dispatch queue used by the ~> operator. */
private let queue = dispatch_queue_create("serial-worker", DISPATCH_QUEUE_SERIAL)
然后,问题就出现了。
在
OperationViewController
中,有一个名为getResults
的方法:private func getResults () -> [(name: String, from: String, result: String)]? {
// irrelevent code about getting the user's inputs from UITextFields
return operation.calculate(input) // This will take a few seconds
}
那里的
calculate
方法需要几秒钟才能返回。前面提到的Calculate按钮有一个连接到
ResultsViewController
的segue。我没有明确地调用performSegueWithIdentifier
。我只是控制拖动按钮到结果视图控制器。在
prepareForSegue
中,我调用getResults
:override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "showOperationHelp" {
// irrelevent
} else if segue.identifier == "showResults" {
let vc = segue.destinationViewController as! ResultsViewController
vc.results = getResults()
}
}
现在我试着把
getResults
部分放到一个背景线程中,方法是:} else if segue.identifier == "showResults" {
let vc = segue.destinationViewController as! ResultsViewController;
{ self.getResults() } ~> { vc.results = $0 };
}
但这不起作用,因为
prepareForSegue
在计算完成之前返回。这意味着当vc.results
返回时nil
就是prepareForSegue
。这将导致ResultsViewController
不显示任何内容。我尝试过的另一种方法是将“do in background”内容放入
getResults
:private func getResults () -> [(name: String, from: String, result: String)]? {
// irrelevent code about getting the user's inputs from UITextFields
var results: [(name: String, from: String, result: String)]?;
{ self.operation.calculate(input) } ~> { results = $0 };
return results
}
同样,
getResults
将返回nil
。在我写C#的时候,我可以使用
async/await
关键字来实现这一点。我能做的就是:
var results = await operations.Calculate(input);
当执行达到
await
时,它会暂停并允许UI线程继续。异步操作完成后,执行将返回到停止的位置并继续。问:我能不能用迅捷的方式做上面的事情?如果我不能,我怎么能等到计算完成并显示
ResultsViewController
?万一你不明白我的意思,我会准确地描述一下我想要什么:
用户输入一些输入
用户点击计算按钮
显示一条消息,告诉用户它正在计算
一段时间后
计算完成
ResultsViewController
显示经过一番努力,我只能得到这个:
用户输入一些输入
用户点击计算按钮
显示一条消息,告诉用户它正在计算
ResultsViewController
显示,没有结果一段时间后
计算完成,但不知道。
另外,我不知道如何改进题目。。。
最佳答案
为了清晰起见,编辑原始响应:
让calculate按钮调用一个名为calculate()的方法或显示活动指示器的其他方法,然后调用getResults方法。
给getResults()一个completionHandler,在成功完成时关闭活动指示器,并用完成的计算执行segue。