Wait for async method before segue

2019-07-25 07:01发布

I have a button and when I press it I´m calling an Async function:

func check(url : String){
        let url = NSURL(string: url)
        print("Checking")
        dispatch_async(dispatch_get_main_queue(), {
            let task = NSURLSession.sharedSession().dataTaskWithURL(url!) {(data, response, error) in
                if error == nil {
                    self.isWorking = true
                }
                else{
                    self.isWorking = false
                    }
                }
            }
            task.resume()
        })
    }

So when I press my button I do the following:

override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!){
        let web = segue.destinationViewController as! ViewController()

        check(url)

        dispatch_async(dispatch_get_main_queue(), {
              if (isWorking){ 
                   // Do stuff
              }
      })
}

The problem is that isWorking is called before the check method is completed.

How can I make sure that check is completed before I make my check for isWorking?

3条回答
一夜七次
2楼-- · 2019-07-25 07:27

You could use a "completion handler":

func check(url : String, completion: (isWorking: Bool)->()) {
    let url = NSURL(string: url)
    print("Checking")
    let task = NSURLSession.sharedSession().dataTaskWithURL(url!) {(data, response, error) in
        if error == nil {
            completion(isWorking: true)
        }
        else{
            completion(isWorking: false)
        }
    }
    task.resume()
}

And you call it like this, with a trailing closure:

check(url) { (isWorking) in
    if isWorking {
        // do stuff
    } else {
        // not working
    }
}
查看更多
兄弟一词,经得起流年.
3楼-- · 2019-07-25 07:29

You can post a notification to a listener to perform the segue only when the task is complete with NSNotificationCenter.defaultCenter().postNotificationName("name", object: nil):

override func viewDidLoad() {
    super.viewDidLoad()

    // Register a notification listener
    NSNotificationCenter.defaultCenter().addObserver(self, selector: "customSegue:", name:"segue", object: nil)
}

func customSegue(notification: NSNotification){
    // Do stuff
}

override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!){
    check(url)
}

func check(url : String){
    let url = NSURL(string: url)
    print("Checking")
    dispatch_async(dispatch_get_main_queue(), {
        let task = NSURLSession.sharedSession().dataTaskWithURL(url!) {(data, response, error) in
            if error == nil {
                self.isWorking = true
                // Send a notification to the listener to perform stuff
                NSNotificationCenter.defaultCenter().postNotificationName("segue", object: nil)
            }
            else{
                self.isWorking = false
                }
            }
        }
        task.resume()
    })
}

This way the code in customSegue func will only be executed when error == nil

查看更多
相关推荐>>
4楼-- · 2019-07-25 07:32

This will do the job:

import UIKit

class AnyViewController: UIViewController
{
    var isWorking = false

    func check(url : String)
    {
        let url = NSURL(string: url)
        print("Checking")

        let task = NSURLSession.sharedSession().dataTaskWithURL(url!) {(data, response, error) in
            if error == nil
            {
             self.performSegueWithIdentifier("mySegueID", sender: nil)
            }
            else{
                self.isWorking = false
            }
        }

        task.resume()
    }
}
查看更多
登录 后发表回答