Comment faire une fermeture optionnelle en swift?

93

J'essaye de déclarer un argument dans Swift qui prend une fermeture facultative. La fonction que j'ai déclarée ressemble à ceci:

class Promise {

 func then(onFulfilled: ()->(), onReject: ()->()?){       
    if let callableRjector = onReject {
      // do stuff! 
    }
 }

}

Mais Swift se plaint que "la valeur liée dans un conditionnel doit être un type facultatif" où le "if let" est déclaré.

Marcosc
la source
Pensez à n'utiliser qu'une seule fermeture avec des paramètres.
catanore

Réponses:

113

Vous devez mettre la fermeture facultative entre parenthèses. Cela permettra d'étendre correctement l' ?opérateur.

func then(onFulfilled: ()->(), onReject: (()->())?){       
    if let callableRjector = onReject {
      // do stuff! 
    }
 }
Cezar
la source
Savez-vous quelle est la raison pour laquelle il faut le mettre entre parenthèses?
Marcosc
5
Probablement pour lever l'ambiguïté. Si la fermeture facultative devait avoir une valeur de retour, il pourrait être difficile de savoir ce que ()->Int?signifie.
Cezar
3
Aussi, dans le livre Swift: «Lors de la déclaration d'un type facultatif, veillez à utiliser des parenthèses pour définir correctement le? opérateur. Par exemple, pour déclarer un tableau facultatif d'entiers, écrivez l'annotation de type sous la forme (Int []) ?; écrire Int []? produit une erreur. »
Cezar
@Cezar Pourriez-vous s'il vous plaît expliquer un peu pourquoi et où utiliser "Fermeture facultative", je suis curieux de le savoir.
iLearner
@Cezar Pas sur un mac pour le moment donc ma syntaxe peut être légèrement décalée, mais rappelez-vous que ?c'est vraiment juste du sucre pour Optional<T>, donc vous pouvez aussi écrire `func then (onFulfilled: () -> (), onReject: Optional <() -> ()>) {`alors vous n'auriez pas besoin de plus (), bien que l'OMI ()?soit plus jolie. Vous pouvez également le rendre encore plus joli avec un typealias comme typealias RejectHandler = () -> () func then(onFulfilled: ()->(), onReject: RejectHandler?) {
Andrew Carter
62

Pour rendre le code encore plus court, nous pouvons utiliser nilcomme valeur par défaut pour le onRejectparamètre et le chaînage facultatif ?()lors de son appel:

func then(onFulfilled: ()->(), onReject: (()->())? = nil) {
  onReject?()
}

De cette façon, nous pouvons omettre le onRejectparamètre lorsque nous appelons la thenfonction.

then({ /* on fulfilled */ })

Nous pouvons également utiliser la syntaxe de fermeture de fin pour passer le onRejectparamètre en thenfonction:

then({ /* on fulfilled */ }) {
  // ... on reject
}

Voici un article de blog à ce sujet.

Evgenii
la source
34

Puisque je suppose que cette fermeture "facultative" ne devrait simplement rien faire, vous pouvez utiliser un paramètre avec une fermeture vide comme valeur par défaut:

func then(onFulfilled: ()->(), onReject: ()->() = {}){       
    // now you can call your closures
    onFulfilled()
    onReject()
}

cette fonction peut maintenant être appelée avec ou sans le onRejectcallback

then({ ... })
then({ ... }, onReject: { ... })

Pas besoin de Swift génial Optionals?ici!

DiegoFrings
la source
C'est une belle solution!
Roland T.27
6

C'est peut-être une manière plus propre. Surtout lorsque la fermeture a des paramètres compliqués.

typealias SimpleCallBack = () -> ()

class Promise {

func then(onFulfilled: SimpleCallBack, onReject: SimpleCallBack?){       
    if let callableRjector = onReject {
        // do stuff! 
    }
}

}
Seifolahi
la source