我正在开发一个计算东西的应用程序。
用户将在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。

09-05 20:20