简体   繁体   English

如何等待 function 在 iOS/Swift 上结束,然后再开始第二个

[英]How to wait for a function to end on iOS/Swift, before starting the second one

I basically have to methods, which are being called in my viewDidLoad.我基本上必须使用在我的 viewDidLoad 中调用的方法。 The first one gets the user's search preferences and saves the preferences to variables at the top.第一个获取用户的搜索偏好并将偏好保存到顶部的变量。 After that I want to access and work with these variables in the second function. But now the variables are always nil when I want to access them in the second function.之后我想在第二个 function 中访问和使用这些变量。但是现在当我想在第二个 function 中访问它们时,变量总是 nil。

How do I need to adjust my viewDidLoad, so the second function is only executed once and my data request has been performed successfully?怎么调整我的viewDidLoad,让第二个function只执行一次,我的数据请求就执行成功了?

var searchLocation = String()
var searchLocationCoordinates = [String:Double]()
var searchRange = Int()


override func viewDidLoad() {
    super.viewDidLoad()

    // Gets the user's search preference
    getTheSearchLocationAndRange()

    // Loads the data from the database
    loadDataFromDatabase()
}

I have read stuff so far with dispatch_asynch or completion handler.到目前为止,我已经阅读了有关 dispatch_asynch 或完成处理程序的内容。 Maybe someone can post some code which I can use in my viewDidLoad and makes it work?也许有人可以发布一些我可以在我的 viewDidLoad 中使用并使其工作的代码?

You can use Swift closures! 你可以使用Swift闭包! They are made for that. 它们是为此而制造的。

Please refer to the Apple guide: Closures 请参阅Apple指南: 闭包

Here's the code you need in your particular case. 这是您在特定情况下需要的代码。

FinishedDownload is the closure. FinishedDownload是关闭。 When getTheSearchLocationAndRange() is called, its code is executed until the completed() line which waits for all processes of the function to finish. getTheSearchLocationAndRange() ,执行其代码直到completed()行等待函数的所有进程完成。 Once the processes finish (downloads for example), completed() calls the closure which activates the code defined in getTheSearchLocationAndRange { () -> () in . 一旦进程完成(例如下载), completed()将调用闭包,该闭包激活getTheSearchLocationAndRange { () -> () in定义的代码。 Therefore, loadDataFromDatabase() is only called once getTheSearchLocationAndRange() has entirely finished executing and the data is present (not nil). 因此,只有在getTheSearchLocationAndRange()完全执行并且数据存在(不是nil)时才调用loadDataFromDatabase() )。

    var searchLocation = String()
    var searchLocationCoordinates = [String:Double]()
    var searchRange = Int()
    typealias FinishedDownload = () -> ()

    override func viewDidLoad() {
        super.viewDidLoad()

        getTheSearchLocationAndRange()
    }

    func getTheSearchLocationAndRange(completed: FinishedDownload) {

           // Code for searching Location Range HERE

           completed()
    }

    getTheSearchLocationAndRange { () -> () in
        loadDataFromDatabase()
    }

I hope this solved your issue and answered your question :) 我希望这解决了你的问题并回答了你的问题:)

BTW, about the "leaving your GUI hanging" part, Alamofire takes automatically care of this for you. 顺便说一句,关于“离开你的GUI挂”部分,Alamofire会自动为您解决这个问题。 If you don't use Alamofire, then you will have to manually assign the asynchronous request to a background thread so your GUI doesn't become unresponsive. 如果您不使用Alamofire,则必须手动将异步请求分配给后台线程,以便您的GUI不会无响应。

I wrote a demo project and posted it on GitHub that simulates handling an asynchronous network download. 我写了一个演示项目并将其发布在GitHub上,模拟处理异步网络下载。 Take a look at DuncanMC/SwiftCompletionHandlers . 看看DuncanMC / SwiftCompletionHandlers

Specifically look at the method asyncFetchImage(), which does almost exactly what this thread is talking about: Uses an asynchronous method internally, and takes a completion block that it calls once the asynchronous load is done. 具体看一下方法asyncFetchImage(),它几乎完全是这个线程所讨论的内容:在内部使用异步方法,并在异步加载完成后接受它调用的完成块。

That is the general pattern you should use. 这是您应该使用的一般模式。 Write a method that takes a completion block/closure. 编写一个完成块/闭包的方法。 Internally, have that method call whatever asynchronous function it needs and then call your completion closure from inside the asynchronous method call's completion closure. 在内部,让该方法调用它需要的任何异步函数,然后从异步方法调用的完成闭包内部调用完成闭包。

The function asyncFetchImage looks like this: asyncFetchImage函数如下所示:

func asyncFetchImage(imageName imageName: String,
  completion: (
    image: UIImage?,
    status: String) -> ())
{
  print("Entering \(#function)")

  //Simulate a network operation by waiting a few seconds before loading an image
  let nSecDispatchTime = dispatch_time(DISPATCH_TIME_NOW, Int64(3.0 * Double(NSEC_PER_SEC)))
  let queue = dispatch_get_main_queue()
  dispatch_after(nSecDispatchTime, queue)
    {
      () -> Void in
      let result = UIImage(named: imageName)
      print("Loading image in background")
      let status = result != nil ? "image loaded" : "Error loading image"
      print("About to call completion handler")
      completion(image: result, status: status)
  }
  print("Leaving \(#function)")
}

Okay I've found an solution. 好的,我找到了解决方案。 I basically called the function at the end of the first one. 我基本上在第一个函数结束时调用了函数。

So basically: 所以基本上:

    var searchLocation = String()
    var searchLocationCoordinates = [String:Double]()
    var searchRange = Int()


    override func viewDidLoad() {
        super.viewDidLoad()

        // Gets the user's search preference
        getTheSearchLocationAndRange()
    }

    func getTheSearchLocationAndRange() {
    // Code for getTheSearchLocationAndRange()

    loadDataFromDatabase()
    }

    func loadDataFromDatabase(){
    // Code for loadDataFromDatabase()
    }

Try this尝试这个

typealias FinishedMethod = ()

override func viewDidLoad() {
    super.viewDidLoad()
    SecondMethod(completed: FirstMethod())
}

func FirstMethod() {
       // FirstMethod Code HERE
}

func SecondMethod(completed: FinishedMethod ) {
       // SecondMethod Code HERE
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM