Я быстро учусь и решил создать простое приложение погоды.У меня проблема с получением данных о погоде в том порядке, в котором я их запрашивал.В моем контроллере представления у меня есть 2 свойства, weatherData и местоположения, которые являются массивами.Когда приложение открывается, я загружаю все сохраненные местоположения из UserDefaults.Затем я перебираю каждое местоположение и делаю несколько сетевых вызовов для получения данных о погоде для каждого местоположения.Я использую группы рассылки, чтобы убедиться, что я жду, пока все данные не будут загружены, прежде чем я использую данные о погоде для загрузки viewModels, которые его используют.Проблема в том, что weatherData не всегда возвращается в том же порядке, который я запрашивал, поэтому индексы location и weatherData не выровнены / не синхронизированы.Я думал, что использование DispatchQueue.main.async будет последовательным и будет выполнять элементы по порядку, но этого не происходит.Я, очевидно, не правильно понимаю, как работает gcd, и я действительно изо всех сил пытаюсь найти решение этой проблемы.Любое руководство будет высоко ценится, спасибо заранее!
Код в viewController
private func updateWeatherData() {
let myGroup = DispatchGroup()
for i in 0..<locations.count {
myGroup.enter()
print("Calling fetch Weather for index: ", i )
self.apiService.fetchWeatherData(for: self.locations[i].location) { (response, error) in
if let error = error {
// Unable to retrieve weather data
self.presentAlert()
} else if let response = response {
print("Finished Request: \(i)")
self.weatherData.append(response)
}
myGroup.leave()
}
}
myGroup.notify(queue: .main) {
print("Finished All requests")
self.locationsTableViewController.viewModel = LocationsViewModel(locations: self.locations, weatherData: self.weatherData)
}
}
Код в моем классе apiService
func fetchWeatherData(for location: CLLocation, completion: @escaping WeatherDataCompletion) {
// Weather request used to return valid api url string based on location
let weatherRequest = WeatherRequest(baseUrl: APIConfiguration.authenticatedBaseUrl, location: location)
URLSession.shared.dataTask(with: weatherRequest.url) { (data, response, error) in
DispatchQueue.main.async {
self.didFetchWeatherData(data: data, response: response, error: error, completion: completion)
}
}.resume()
}
// Error checks and decodes network data response
private func didFetchWeatherData(data: Data?, response: URLResponse?, error: Error?, completion: WeatherDataCompletion) {
if let error = error {
completion(nil, .failedRequest)
print("No WeatherData Available: ", error)
} else if let data = data, let response = response as? HTTPURLResponse {
if response.statusCode == 200 {
do {
// Decode JSON
let weatherData = try decoder.decode(DarkSkyResponse.self, from: data)
completion(weatherData, nil)
} catch {
print("Unable to Decode JSON: ", error)
completion(nil, .invalidResponse)
}
} else {
print("Status Code: ", response.statusCode)
completion(nil, .failedRequest)
}
} else {
completion(nil, .unknown)
}
}
РЕДАКТИРОВАТЬ: Как уже упоминалось, ответЯ узнал, что URLSession не гарантирует порядок.В итоге я просто сохранил каждый результат по индексу в начальном цикле.