Tengo un controlador de finalización que se llama dentro de mi cierre. Sin embargo, el controlador de finalización solo se llama cuando todo va bien. En el caso de un error, nunca se llama al controlador de finalización.
func product(with id: String, _ completion: @escaping (Product) -> ()) { // Make a network request for the product ... if (product) { completion(product) } }¿Es este un mal diseño? Recientemente recibí el comentario de que los controladores de finalización deben llamarse incluso en caso de errores, de lo contrario, la persona que llama estará esperando indefinidamente. Nunca había escuchado eso antes y ahora me pregunto si esto se aplica a Swift.
Estrictamente hablando, la persona que llama no espera nada. El código en el cierre se ejecutará o no.
Sin embargo, también es una buena práctica devolver errores.
Una forma inteligente es el tipo de Result
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)) } }y llámalo
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 } } Nota: El carácter de subrayado antes de la completion en la declaración de la función no tiene sentido.
Si no llama a una finalización, no sucederá nada porque la persona que llama a la finalización no lo esperará.
Pero si desea cubrir todos los casos, intente agregar una devolución de llamada fallida. Por ejemplo:
func product(with id: String, _ success: @escaping (Product) -> (), failure: @escaping (Any) -> ())En su caso, si lo está tratando como una finalización , significa que debe llamarse sin importar cuál sea el caso (éxito de falla con error), debe regresar cuando se completó el proceso.
Lo que podría hacer es pasar un error opcional y product al cierre de finalización y luego verificar si el error es nil o no:
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) }Llamando al método:
product(with: "ID") { (product, error) in guard let returnedError = error else { print(product) return } print(returnedError) }O:
product(with: "ID") { (product, error) in if let returnedError = error { print(returnedError) return } print(product) }