Определите, когда urlsession.shared и парсинг Json будут завершены

Я загружаю, а затем читаю файл json. этот json содержит список файлов и их адрес на сервере.

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

но у меня возникли проблемы с настройкой блока завершения, который указывал бы, что все завершено.

вот код.

   jsonAnalysis {
        self.sum = self.sizeArray.reduce(0, +)
        print(self.sum)
    } here

func jsonAnalysis(completion:  @escaping () -> ()) {


    let urlString = "xxxxxxxxxxxxxxxxxxxxx"
    let url = URL(string: urlString)
    URLSession.shared.dataTask(with:url!) { (data, response, error) in
        if error != nil {
            print("error")

        } else {
            do {

                let json = try JSONSerialization.jsonObject(with: data!, options: .mutableContainers) as? [String: Any]
                self.i = -1
                guard let array = json?["Document"] as? [Any] else { return }

                for documents in array {

                    self.i = self.i + 1
                    guard let VersionDictionary = documents as? [String: Any] else { return }
                    guard let DocumentName = VersionDictionary["documentname"] as? String else { return }
                    guard let AddressServer = VersionDictionary["addressserver"] as? String else { return }

                    self.resultAddressServer.append(AddressServer)
                    self.addressServer = self.resultAddressServer[self.i]
                    self.resultDocumentName.append(DocumentName)
                    self.documentName = self.resultDocumentName[self.i]

                    let url1 = NSURL(string: AddressServer)
                    self.getDownloadSize(url: url1! as URL, completion: { (size, error) in
                        if error != nil {
                            print("An error occurred when retrieving the download size: \(String(describing: error?.localizedDescription))")
                        } else {
                            self.sizeArray.append(size)
                            print(DocumentName)
                            print("The download size is \(size).")

                        }
                    })

                }

            } catch {
                print("error")
            }

        }
            completion()

        }   .resume()

}

func getDownloadSize(url: URL, completion: @escaping (Int64, Error?) -> Void) {
    let timeoutInterval = 5.0
    var request = URLRequest(url: url,
                             cachePolicy: .reloadIgnoringLocalAndRemoteCacheData,
                             timeoutInterval: timeoutInterval)
    request.httpMethod = "HEAD"
    URLSession.shared.dataTask(with: request) { (data, response, error) in
        let contentLength = response?.expectedContentLength ?? NSURLSessionTransferSizeUnknown
        completion(contentLength, error)
        }.resume()
}

Я хотел бы получить сумму массива в конце, когда все будет сделано, прямо сейчас print(self.sum) выполняется раньше и показывает 0.

Я не знаком с завершением и уверен, что делаю все неправильно.


person Julien7377    schedule 06.09.2018    source источник


Ответы (1)


Вам нужно DispatchGroup.

Перед вызовом внутренней асинхронной задачи enter в блоке завершения внутренней асинхронной задачи leave укажите группу.
Наконец, когда группа notifies, вызовите completion

let group = DispatchGroup()
for documents in array {
    ...

    let url1 = URL(string: AddressServer) // no NSURL !!!
    group.enter()
    self.getDownloadSize(url: url1!, completion: { (size, error) in
         if error != nil {
            print("An error occurred when retrieving the download size: \(String(describing: error?.localizedDescription))")
         } else {
            self.sizeArray.append(size)
            print(DocumentName)
            print("The download size is \(size).")
         }
         group.leave()
     })
}
group.notify(queue: DispatchQueue.main) {
    completion()
}
person vadian    schedule 06.09.2018
comment
Он работает отлично и дает мне общий размер в конце, как и ожидалось. Спасибо! - person Julien7377; 06.09.2018
comment
Вы всегда можете обернуть асинхронный вызов в другой и использовать один обратный вызов, как только вы запустите его, а другой — после завершения. Подобно тому, как UIAnimation принимает два блока. См. здесь - person Honey; 28.12.2019