city parking city parking - 5 months ago 27
iOS Question

How to perform segue after information from protocol is recieved

I have a button in a cell which calls a protocol that has data that needs to be passed to the view controller by the segue. The segue is happening through storyboard. My current code uses the

shouldperformsegue
to return no when the button is pressed as the first segue that happens does not have the data.
Im guessing the segue and the protocol are being handled asynchronously.

But before I return NO I tell it to perform the segue at a delay. This delayed segue does have the data and works fine.

My question is there a way to wait for the protocol to finish and then perform the segue? Maybe with an execution block?

Answer

The other responders have hinted about this, but haven't stated it explicitly, so here goes.

Do not tie a segue directly to the button. Instead, control-drag from the source view controller SCENE to the destination scene to create a segue at the view controller level. Give the segue a unique identifier.

Then, in your button IBAction code, do the async network download. You may want to display a "loading, please wait" message or something while the download is taking place. Most async network calls take a completion block. In that completion block, wrap a call to performSegueWithIdentifier in a call to dispatch_async(dispatch_get_main_queue() so the segue gets invoked on the main thread. (@SantaClaus's answer shows the syntax for that.)

So your button IBAction code might look like this:

- (IBAction) buttonAction: (UIButton *) sender;
{
  //Display a "please wait"message to the user if desired
  doAsyncCallTakingBlock( completion: ^(NSData *data)
  {
    //parse the data, (or whatever)

    dispatch_async(dispatch_get_main_queue(), ^
    {
      //This call uses the button as the sender. That might be appropriate,
      //or not. 
      [self performSegueWithIdentifier:@"jumpToOtherViewController" 
        sender: sender];
    });
  }
}

With this approach the segue doesn't get called until the async method (Which I called doAsyncCallTakingBlock in my example code) has finished it's work. You might call an Alamofire request method, use an NSURLSession, or any other async method that takes a completion block.