简体   繁体   中英

Swift 5 Coordinating background tasks

I am still trying to understand and control asynch tasks. I have an app which is generating multiple API calls to different providers. I could have a maximum of 367 API calls in parallel. How can I coordinate all of these so I can know when the first one starts and the last one is completed?

With help from this forum, I can get this working with single calls, but not multiple.

My call to the API from a class is below (relevant sections, which show the use of .completion:

let session = URLSession.shared
    let url = components.url!
    let request = URLRequest(url: url)

    session.dataTask(with: request) { data, response, error in
        if let error = error {
            DispatchQueue.main.async {
                completion(.failure(error))
            }
            return
        }

        guard
            let responseData = data,
            let httpResponse = response as? HTTPURLResponse,
            200 ..< 300 ~= httpResponse.statusCode
        else {
            DispatchQueue.main.async {
                completion(.failure(AstronomicalTimesError.invalidResponse(data, response)))
            }
            return
        }

        do {
            print("Astronomical times api completed with status code ", httpResponse.statusCode)
            let astronomicalTimesResponse = try JSONDecoder().decode(AstronomicalTimesResponse.self, from: responseData)
            DispatchQueue.main.async {
                completion(.success(astronomicalTimesResponse))
                //print("astronomical times loaded ", astronomicalTimesResponse)
            }
        } catch let jsonError {
            DispatchQueue.main.async {
                completion(.failure(jsonError))
            }
        }
    }.resume()

This is then called for each day in a date range.

repeat {
        let astronomicalTimes = AstronomicalTimes(date: astRetrievalDate, latitude: station.lat, longitude: station.long)

        astronomicalTimes.start { result in
            switch result {
                case .success(let astronomicalTimesResponse):
                    let detail = DayDetails(date: astRetrievalDate, astronomicalTimes: astronomicalTimesResponse.results)
                    details.append(detail)
                case .failure(let error):
                    print("Astronomical Times API call from saved tides failed with error \(error)")
            }
        }
        astRetrievalDate = astRetrievalDate.dayAfter
    } while astRetrievalDate.noon <= toDate.noon

    let tideToSave = SavedTides(saveKey: key, details: details)
    savedTides.append(tideToSave)
    print("saved tide details: ", savedTides)

I want to build up the results in savedTides but, the all the API's complete after the assignment to savedTides so this is always empty. Note that I will also be firing off another two separate API's to different providers so I need all of these to complete before I assign the results of all of them to an array.

Why don't you have a look at promises? so you can fire other call whenever the others that you need to complete before are done.

https://github.com/mxcl/PromiseKit

You can group multiple promises in an array and fire them all together, or maybe a DispatchGroup could help you.

Thanks all. DispatchGroup was the answer. I was really struggling to understand how to use it from the apple documentation, however I came across this excellent tutorial and all was clear. How to use DispatchGroup in Swift 4.2

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM