¿Cómo se hace un cierre opcional en Swift?

93

Estoy tratando de declarar un argumento en Swift que tiene un cierre opcional. La función que he declarado se ve así:

class Promise {

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

}

Pero Swift se queja de que "el valor enlazado en un condicional debe ser un tipo opcional" donde se declara el "if let".

Marcosc
fuente
Considere usar solo un cierre con parámetros.
catanore

Respuestas:

113

Debe incluir el cierre opcional entre paréntesis. Esto analizará adecuadamente al ?operador.

func then(onFulfilled: ()->(), onReject: (()->())?){       
    if let callableRjector = onReject {
      // do stuff! 
    }
 }
Cezar
fuente
¿Sabe cuál es la justificación de tener que encerrarlo entre paréntesis?
Marcosc
5
Probablemente para eliminar la ambigüedad. Si el cierre opcional tuviera un valor de retorno, podría resultar confuso en cuanto a qué ()->Int?significa.
Cezar
3
Además, del libro Swift: “Al declarar un tipo opcional, asegúrese de utilizar paréntesis para definir correctamente el alcance de? operador. Como ejemplo, para declarar una matriz opcional de enteros, escriba la anotación de tipo como (Int []) ?; escribiendo Int []? produce un error ".
Cezar
@Cezar ¿Podría explicar un poco por qué y dónde usar "Cierre opcional"? Tengo curiosidad por saber esto.
iLearner
@Cezar No en una Mac en este momento, por lo que mi sintaxis puede estar un poco fuera de lugar, pero recuerde ?que en realidad es solo azúcar Optional<T>, por lo que también podría escribir `func then (onFuldered: () -> (), onReject: Optional <() -> ()>) {`entonces no necesitarías el extra (), aunque IMO ()?es más bonito. También puedes hacerlo aún más bonito con un tipo de letra como typealias RejectHandler = () -> () func then(onFulfilled: ()->(), onReject: RejectHandler?) {
Andrew Carter
62

Para hacer el código aún más corto, podemos usar nilcomo valor predeterminado para el onRejectparámetro y el encadenamiento opcional ?()al llamarlo:

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

De esta forma podemos omitir el onRejectparámetro cuando llamamos a la thenfunción.

then({ /* on fulfilled */ })

También podemos usar la sintaxis de cierre final para pasar el onRejectparámetro a la thenfunción:

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

Aquí hay una publicación de blog al respecto.

Evgenii
fuente
34

Dado que supongo que este cierre "opcional" simplemente no debería hacer nada, podría usar un parámetro con un cierre vacío como valor predeterminado:

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

esta función ahora se puede llamar con o sin la onRejectdevolución de llamada

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

¡No es necesario que Swift sea increíble Optionals?aquí!

DiegoFrings
fuente
¡Esta es una buena solución!
Roland T.
6

Quizás sea una forma más limpia. Especialmente cuando el cierre tiene parámetros complicados.

typealias SimpleCallBack = () -> ()

class Promise {

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

}
Seifolahi
fuente