简体   繁体   中英

How to pass a closure in performSegue's sender parameter?

In my iOS App, I would like to ask the user a question and then take some actions depending on the answer.

In many other programming frameworks I would have used a modal dialog that waits for the user to enter the result and then returns that result to the main code. But, to my knowledge, the UIKit framework does not contain such modal dialogs . Instead I use a modal segue , but since the call to performSegue returns immediately the programming becomes somewhat messy...

The performSegue has a sender parameter of kind Any? . Can I use that parameter to pass a closure with the code to be executed when the user exits the segue? And, if so, how?

I don't think that's possible with performSegue but you could use prepareForSegue to send values when the segue is performed.

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {        
    let vc = segue.destination as! MyViewController
    vc.myParameter = myValue

}

but if you just want to give the user a dialog and wait for the answer there's another way to do that.

you could make a viewController with default background which will make it hidden and then add a View inside it and customize it however you want, you can consider it as an Alert. and then initiate it when you want to ask the user for the data.

let vc = self.storyboard?.instantiateViewController(withIdentifier: "alert") as! AlertViewController
vc.definesPresentationContext = true
vc.modalPresentationStyle = UIModalPresentationStyle.overCurrentContext
//Here you can pass data into the viewController you're initiating
vc.myParameter = myValue
self.present(vc,animated: false,completion: nil)

this way the UIView you customized in the viewController will appear just like a normal alert over the current viewController.

At the time of writing this question has three down votes! I can't see why. In my opinion my question is clearly stated.

It is possible to use performSegue and prepare(for:sender:) . But using instantiateViewController requires less setup work.

Here is a solution based on Yasser's answer :

In storyboard I created a view controller ( PawnPromotionVC ) with a semi transparent white background view, and a non transparent smaller sub view containing the "dialog". The view controller has a onExit attribute declared as follows:

   var onExit : ((Piece) -> Void)?

Below is the action handler for button tapps in that view controller (by the way, the objective of the "dialog" is to asks the user what chess piece a pawn should be promoted to):

  @IBAction func pieceButtonTapped(_ sender: UIButton) {
        let piece = Piece(rawValue: sender.tag)!

        if let run = onExit {
            run( piece )
        }
        dismiss(animated: true, completion: nil)
    }

To launch the dialog I call

  if ... {
      runPawnPromotionDialog(){
          (piece:Piece) in
           print("the pawn should be promoted to a \(piece)" )
           ...
           ...
      }
  }

from my mainViewController . The function runPawnPromotionDialog , also implemented in the mainViewController, is almost implemented as suggested by Yasser:

  func runPawnPromotionDialog( onExit: @escaping (Piece) -> Void ){

        let vc = self.storyboard?.instantiateViewController(withIdentifier: "PawnPromotionVC") as! PawnPromotionVC

        vc.definesPresentationContext = true
        vc.modalPresentationStyle = UIModalPresentationStyle.overCurrentContext
        vc.modalTransitionStyle = .crossDissolve

        vc.onExit = onExit
        self.present(vc,animated: false,completion: nil)
    }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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