Как мне получить ответ от URLSession до выполнения остальной части моего кода? - PullRequest
0 голосов
/ 05 августа 2020

У меня проблема с моим URLSession в Swift. Независимо от того, что я пробую (или сколько руководств я прочитал), я не могу найти способ получить сетевой запрос к fini sh до того, как выполнит остальную часть моего кода. У меня создалось впечатление, что обработчик завершения сделает свое дело, но оказалось, что это не так. Что я здесь делаю не так?

struct DataManager {
    
    let eventsURL = URL(string: "https://spreadsheets.google.com/feeds/list/blablabla/1/public/full?alt=json")!
    let decoder = JSONDecoder()
    var data = Data()
    
    func downloadEvents() -> [Event] {
        var events: [Event] = []
        var downloadedEvents: [[String: Any]] = []
        
        getDataFromServer(forURL: eventsURL) { result in
            downloadedEvents = result
        }
        
        // This next part always executes before the response is receive, which means the downloadedEvents variable is always empty.

        for downloadedEvent in downloadedEvents {
            if let event = Event(fromJSON: downloadedEvent) {
                events.append(event)
            }
        }
        
        return events
    }
    
    func getDataFromServer(forURL url: URL, completion: @escaping (_ result: [[String: Any]]) -> Void) {
        URLSession.shared.dataTask(with: url) { data, response, error in
            if let jsonData = data {
                let jsonObject = try? JSONSerialization.jsonObject(with: jsonData, options: [])
                if let dictionary = jsonObject as? [String: Any] {
                    if let feed = dictionary["feed"] as? [String: Any] {
                        if let entry = feed["entry"] as? [[String: Any]] {
                            DispatchQueue.main.async {
                                completion(entry)
                            }
                        }
                    }
                }
            }
        }.resume()
    }
}

1 Ответ

1 голос
/ 05 августа 2020

Ваша функция downloadEvents должна быть асинхронной, потому что ее вызовы другая асинхронная функция getDataFromServer.

Решением может быть перемещение части для вычисления событий в асинхронный блок и укажите параметр завершения:

func downloadEvents(completion: @escaping ([Event]) -> ()) {
    var events: [Event] = []
    var downloadedEvents: [[String: Any]] = []

    getDataFromServer(forURL: eventsURL) { result in
        downloadedEvents = result
        for downloadedEvent in downloadedEvents {
            if let event = Event(fromJSON: downloadedEvent) {
                events.append(event)
            }
        }
        completion(events)
    }
}

Примечание

Ваш код может быть упрощен до:

func downloadEvents(completion: @escaping ([Event]) -> ()) {
    getDataFromServer(forURL: eventsURL) { completion($0.compactMap(Event.init(fromJSON:))) }
}
...