3
votes

Avons-nous toujours besoin d'appeler un gestionnaire d'achèvement à l'intérieur d'une fermeture?

J'ai un gestionnaire de complétion qui est appelé dans ma fermeture. Cependant, le gestionnaire d'achèvement n'est appelé que lorsque tout se passe bien. En cas d'erreur, le gestionnaire de complétion n'est jamais appelé.

func product(with id: String, _ completion: @escaping (Product) -> ()) {

     // Make a network request for the product
     ...

    if (product) {
       completion(product)
    }
}

Est-ce une mauvaise conception? J'ai récemment reçu le commentaire selon lequel les gestionnaires de complétion doivent être appelés même en cas d'erreur, sinon l'appelant attendra indéfiniment. Je n'ai jamais entendu cela auparavant et maintenant je me demande si cela s'applique à Swift.


0 commentaires

3 Réponses :


1
votes

Si vous n'appelez pas une complétion, rien ne se passera car l'appelant de la complétion ne l'attendra pas.

Mais si vous voulez couvrir tous les cas, essayez d'ajouter un rappel d'échec. Par exemple:

func product(with id: String, _ success: @escaping (Product) -> (), failure: @escaping (Any) -> ())


0 commentaires

1
votes

Dans votre cas, si vous le traitez comme un achèvement , cela signifie qu'il doit être appelé quel que soit le cas (succès de l'échec avec erreur), il doit revenir lorsque le processus terminé.

Ce que vous pouvez faire est de transmettre une erreur facultative et un produit à la clôture de la fin, puis vérifier si l'erreur est nulle ou pas:

product(with: "ID") { (product, error) in
    if let returnedError = error {
        print(returnedError)
        return
    }

    print(product)
}

Appel de la méthode:

product(with: "ID") { (product, error) in
    guard let returnedError = error else {
        print(product)

        return
    }

    print(returnedError)
}

Ou:

func product(with id: String, _ completion: @escaping (Product?, Error?) -> ()) {
    // in case of there is an error:
    completion(nil, error)
    return

    // if things went happy:
    completion(product, nil)
}


0 commentaires

6
votes

En parlant strictement, l'appelant n'attend pas du tout. Le code de la fermeture sera exécuté ou non.

Cependant, il est également recommandé de renvoyer des erreurs.

Une méthode intelligente est le Result type

product(with: "Foo") { result in
   switch result {
     case .success(let product): // do something with the product
     case .failure(let error): // do something with the error
   }
}

Et appelez-le

func product(with id: String, completion: @escaping (Result<Product,Error>) -> Void) {

     // Make a network request for the product
     ...
    if error = error { completion(.failure(error)); return }

    if product {
       completion(.success(product))
    } else {
       let error = // create some other error
       completion(.failure(error))
    }
}

Remarque: le caractère de soulignement avant completion dans la déclaration de fonction est inutile.


0 commentaires