web-dev-qa-db-fra.com

Passer des fonctions en tant que paramètres dans Swift

La fonction suivante fonctionne comme prévu dans iOS 8:

func showConfirmBox(msg:String, title:String,
    firstBtnStr:String,
    secondBtnStr:String,
    caller:UIViewController) {
        let userPopUp = UIAlertController(title:title,
            message:msg, preferredStyle:UIAlertControllerStyle.Alert)
        userPopUp.addAction(UIAlertAction(title:firstBtnStr, style:UIAlertActionStyle.Default,
            handler:{action in}))
        userPopUp.addAction(UIAlertAction(title:secondBtnStr, style:UIAlertActionStyle.Default,
            handler:{action in}))
        caller.presentViewController(userPopUp, animated: true, completion: nil)
}

Je voudrais faire quelque chose comme ceci, afin de passer comme arguments les méthodes à exécuter lorsque l’un ou l’autre des boutons va être touché:

func showConfirmBox(msg:String, title:String,
    firstBtnStr:String, firstSelector:Selector,
    secondBtnStr:String, secondSelector:Selector,
    caller:UIViewController) {
        let userPopUp = UIAlertController(title:title,
            message:msg, preferredStyle:UIAlertControllerStyle.Alert)
        userPopUp.addAction(UIAlertAction(title:firstBtnStr, style:UIAlertActionStyle.Default,
            handler:{action in caller.firstSelector()}))
        userPopUp.addAction(UIAlertAction(title:secondBtnStr, style:UIAlertActionStyle.Default,
            handler:{action in caller.secondSelector()}))
        caller.presentViewController(userPopUp, animated: true, completion: nil)
}

Évidemment, je ne fais pas ce qui est juste avec firstSelector et secondSelector, car ce que j'ai essayé jusqu'à présent n'a pas fonctionné. Je suppose que je n'utilise pas la bonne syntaxe pour ce que je veux, mais je suis sûr qu'il est possible de faire ce que je voudrais faire. Une idée de la façon de le faire correctement?

27
Michel

Oneword répond à votre question est Fermetures

La syntaxe par défaut pour les fermetures est () -> ()

Au lieu de Selector, vous pouvez directement mentionner la définition de la méthode

func showConfirmBox(msg:String, title:String,
    firstBtnStr:String, firstSelector:(sampleParameter: String) -> returntype,
    secondBtnStr:String, secondSelector:() -> returntype,
    caller:UIViewController) {
    //Your Code
}

Mais en utilisant cela créera des problèmes lisibles, je vous suggère donc d'utiliser typeAlias

typealias MethodHandler1 = (sampleParameter : String)  -> Void
typealias MethodHandler2 = ()  -> Void

func showConfirmBox(msg:String, title:String,
                    firstBtnStr:String, firstSelector:MethodHandler1,
                    secondBtnStr:String, secondSelector:MethodHandler2) {

    // After any asynchronous call
    // Call any of your closures based on your logic like this
    firstSelector("FirstButtonString")
    secondSelector()
}

Vous pouvez appeler votre méthode comme ça

func anyMethod() {
   //Some other logic 

   showConfirmBox(msg: "msg", title: "title", firstBtnStr: "btnString", 
         firstSelector: { (firstSelectorString) in
              print(firstSelectorString) //this prints FirstButtonString
         }, 
         secondBtnStr: "btnstring") { 
           //Invocation comes here after secondSelector is called

         }
}
57
iPrabu

J'ai écrit cette routine à partir de divers exemples de sites. Voici comment j'appelle la routine ...

@IBAction func buttonClick(_ sender: Any) {
    SS_Alert.createAlert(parmTitle: "Choose", parmMessage: "Please select Yes or No", parmOptions: ["Yes","No","Cancel"], parmFunctions: [testYes, testNo, nil])
}

func testYes() {
    print("yes")
}

func testNo() {
    print("no")
}

Vous pouvez transmettre les options des boutons et les fonctions à exécuter lorsque les boutons sont sélectionnés. Il a fallu un peu de temps pour comprendre comment passer des fonctions en tant que paramètres, mais cela semble bien fonctionner maintenant. J'ai rencontré un problème étrange lorsque j'essayais d'utiliser des boucles pour ajouter des boutons de façon dynamique. J'ai finalement abandonné et utilisé un commutateur/boîtier. J'ai inclus le code de boucle que j'ai essayé d'utiliser, si quelqu'un peut comprendre ce que je faisais mal, faites le moi savoir. Merci.

https://github.com/blakeguitar/iOS/blob/0e243d13cb2decd6e1dbe134a8a046c2caed3876/SS_Alert.Swift

1
Blake Martin