如何以正确的方式在Swift中调度函数? [英] How do I dispatch functions in Swift the right way?

查看:64
本文介绍了如何以正确的方式在Swift中调度函数?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直在努力,但我只是不明白。我对编程很陌生,所以几乎每一个新步骤都是一个实验。虽然我在没有参数/返回的情况下调度普通闭包没有问题,但到目前为止我还没有理解如何处理带有(多个)参数并最终返​​回的函数。



<为了获得正确的解决方案的逻辑,如果有人可以发布一个实际的例子,那将是很好的,所以我可以看到我是否已经完全正确。我会非常感谢任何帮助...如果其他一些实际例子以更好的方式说明了这个话题,请继续自己做!



让我们假设我们想将以下函数异步调度到具有低优先级的后台队列(或者我犯了错误,在定义函数时尝试实现调度而不是等到从其他地方调用它?!):

  func mutateInt(someInt:Int) - > Int {
someHeavyCalculations
返回结果
}

或一个具有多个参数的函数,此外在某个时刻调用第一个函数(后台队列中的所有内容):

  func someBadExample(someString :String,anotherInt:Int) - > Int {
someHeavyStuff
println(testString)
mutateInt(testInt)
返回结果
}

或者应该确保在主队列上运行的UI函数(只是一个虚构的例子):

 覆盖func tableView(tableView:UITableView,numberOfRowsInSection section:Int) - > Int {
let sectionInfo = self.fetchedResultsController.sections?[section] as NSFetchedResultsSectionInfo
return sectionInfo.numberOfObjects
}


解决方案

假设您有类似的功能:

  func calculate(foo:String,bar:Int) - > Int {
//在这里执行缓慢的计算

返回结果
}

如果你想异步这样做,你可以把它包装成这样的东西:

  func calculate( foo:String,bar:Int,completionHandler:@escaping(Int) - > Void){
DispatchQueue.global()。async {
//在这里执行的慢计算

completionHandler(结果)
}
}

或者,如果你想要确保总是在主队列上调用完成处理程序,你也可以这样做:

  func calculate(foo:String,bar:Int,completionHandler:@escaping(Int) - > Void){
DispatchQueue.global()。async {
//在这里执行的慢速计算

DispatchQueue.main.async {
completionHandler(result)
}
}
}

对于在后台执行的工作,您可以使用不同的优先级后台队列,也可以使用自己的自定义队列或自己的操作队列。但是这些细节对于手头的问题并不重要。



相关的是,即使基础同步,此函数本身也不会返回任何值功能呢。相反,此异步呈现通过 completionHandler 闭包将值传回。因此,您可以这样使用它:

  calculate(foo:life,bar:42){result in 
//我们可以在这里使用`result`(例如更新模型或UI)

print(结果是= \(结果))
}

//但是不要试图在这里使用`result`,因为我们立即到达这里,在
之前//上面的慢速异步过程完成了

(仅供参考,以上所有示例均为Swift 3.对于Swift 2.3再现,请参阅此答案的先前版本。)


I've kept trying but I just don't get it. I'm rather new to programming so almost every new step is an experiment. Whereas I have no problems dispatching normal closures without arguments/returns, I haven't understood so far how to deal with functions that take (multiple) arguments and return in the end.

To get the logic of the proper "work around" it would be great if someone could post a practical example so I could see whether I've got all of it right. I'd be very thankful for any kind of help... If some other practical example illustrate the topic in a better way, please go ahead with your own!

Let's say we'd like to asynchronously dispatch the following function to a background queue with low priority (or do I make the mistake, trying to implement the dispatch when defining a function instead of waiting till it is called from somewhere else?!):

func mutateInt(someInt: Int) -> Int {
    "someHeavyCalculations"
    return result
}

or a function with multiple arguments that in addition calls the first function at some point (everything in background queue):

func someBadExample(someString: String, anotherInt: Int) -> Int {
    "someHeavyStuff"
    println(testString)
    mutateInt(testInt)
    return result
}

or a UI-function that should be ensured to run just on main queue (just a fictitious example):

override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {        
    let sectionInfo = self.fetchedResultsController.sections?[section] as NSFetchedResultsSectionInfo       
    return sectionInfo.numberOfObjects
}

解决方案

Let's say you had some function like so:

func calculate(foo: String, bar: Int) -> Int {
    // slow calculations performed here

    return result
}

If you wanted to do that asynchronously, you could wrap it in something like this:

func calculate(foo: String, bar: Int, completionHandler: @escaping (Int) -> Void) {
    DispatchQueue.global().async {
        // slow calculations performed here

        completionHandler(result)
    }
}

Or, alternatively, if you want to ensure the completion handler is always called on the main queue, you could have this do that for you, too:

func calculate(foo: String, bar: Int, completionHandler: @escaping (Int) -> Void) {
    DispatchQueue.global().async {
        // slow calculations performed here

        DispatchQueue.main.async {           
            completionHandler(result)
        }
    }
}

For the work being performed in the background, you may use a different priority background queue, or your might use your own custom queue or your own operation queue. But those details aren't really material to the question at hand.

What is relevant is that this function, itself, doesn't return any value even though the underlying synchronous function does. Instead, this asynchronous rendition is passing the value back via the completionHandler closure. Thus, you would use it like so:

calculate(foo: "life", bar: 42) { result in
    // we can use the `result` here (e.g. update model or UI accordingly)

    print("the result is = \(result)")
}

// but don't try to use `result` here, because we get here immediately, before
// the above slow, asynchronous process is done

(FYI, all of the above examples are Swift 3. For Swift 2.3 rendition, see previous version of this answer.)

这篇关于如何以正确的方式在Swift中调度函数?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆