我应该在哪里放置应该在后台完成的代码?

时间:2016-05-29 05:12:40

标签: ios swift asynchronous

我正在构建一个计算内容的应用程序。

用户将在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方法需要几秒钟才能返回。

前面提到的计算按钮有一个连接到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返回时nilprepareForSegue。这将导致ResultsViewController不显示任何内容。

我尝试的另一种方法是在getResults中将“do in background”放入其中:

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线程继续运行。异步操作完成后,执行将返回到已停止的位置并继续。

问题:我可以在Swift中执行上述操作吗?如果我不能,我怎么能等到计算完成并显示ResultsViewController

万一你不理解我,我会准确描述我想要的东西:

  1. 用户输入一些输入
  2. 用户点击计算按钮
  3. 显示一条消息告诉用户正在计算
  4. 一段时间后
  5. 计算完成
  6. 显示
  7. ResultsViewController
  8. 经过一番尝试,我只能得到这个:

    1. 用户输入一些输入
    2. 用户点击计算按钮
    3. 显示一条消息告诉用户正在计算
    4. 显示
    5. ResultsViewController,但没有结果
    6. 一段时间后
    7. 计算完成但ResultsViewController不知道。
    8. P.S。我不知道如何改进问题标题......

1 个答案:

答案 0 :(得分:2)

为了清晰起见,编辑原始回复:

  • 让compute按钮调用一个名为calculate()的方法或显示活动指示符的方法,然后调用getResults方法。

  • 给getResults()一个completionHandler,并在成功完成时关闭活动指示符并用完成的计算执行segue。