El controlador de finalización siempre devuelve un array vacío, excepto cuando es llamado desde el código que popula el array.
Estoy teniendo algunas dificultades con el controlador de finalización. No quiero usar la nueva función async / await hasta aprender la forma antigua.
Esta es mi función fetch() con @escaping:
func fetch(completion: @escaping (Result<[CountriesFinal], CountryError>) -> Void) {
let urlString = “https://raw.githubusercontent.com/fdsfdghjfvghdfhf.json”
let url = URL(string: urlString)!
let _ = URLSession.shared.dataTask(with: url) { data, _, _ in
guard let jsonData = data else {
completion(.failure(.noDataAvailable))
return
}
do {
let decoder = JSONDecoder()
let countriesResponse = try decoder.decode(Country.self, from: jsonData)
let countryDetails = countriesResponse.countries
completion(.success(countryDetails))
} catch {
completion(.failure(.canNotProcessData))
}
}.resume()
}
He aprendido que fetch() debe ser llamado de esta forma dentro de viewDidLoad():
// var countriess = CountriesFinal // fuera de viewDidLoad
fetch { result in
switch result {
case let .failure(error):
print(error)
case let .success(holidays):
self.countriess = holidays
print(self.countriess[0].name) // FUNCIONA ✔️
}
}
// Si se escribe aquí o en cualquier otra función:
print(self.countriess[0].name) // Thread 1: Fatal error: Index out of range
davy.ai
Respuesta del Experto en IT
Parece que estás experimentando un problema relacionado con el tiempo de tu código asíncrono. El controlador de finalización que estás utilizando es un cierre de escape que se llama después de que se completa la solicitud de red. Esto significa que tu función
fetch
devuelve inmediatamente y el resto de tu código sigue ejecutándose mientras se realiza la solicitud de red.Cuando intentas acceder a
self.countriess
inmediatamente después de llamar a la funciónfetch
, es posible que los datos aún no se hayan cargado, lo que hace que aparezca un error de “Índice fuera de rango”.Para solucionarlo, debes acceder a
self.countriess
solo dentro del controlador de finalización después de haber recibido una respuesta exitosa del servidor. Esto garantiza que los datos se hayan cargado antes de intentar acceder a ellos.Si necesitas acceder a
self.countriess
desde otra función o parte de tu código, debes asegurarte de hacerlo solo después de que se haya llamado al controlador de finalización y se hayan cargado los datos.Alternativamente, puedes usar un
DispatchGroup
para sincronizar tu código y esperar a que se complete la solicitud de red antes de continuar. Sin embargo, esto puede hacer que tu código sea más complejo y difícil de leer.En cuanto a la función
async
/await
, es una forma más nueva de manejar el código asíncrono que facilita la escritura y la lectura. Sin embargo, si quieres aprender primero la forma antigua, eso está perfectamente bien. Solo asegúrate de ser consciente de los posibles problemas y de manejar tu código asíncrono correctamente.