Сделайте несколько сетевых запросов на Swift - PullRequest
2 голосов
/ 18 июня 2020

Я пытаюсь загрузить данные с сайта каталога школьных курсов. У меня 64 URL-адреса в переменной UrlBook. Я успешно написал код для загрузки коллекции курсов и превращения их в один объект subject из одного URL-адреса с использованием метода обработчика завершения. Я действительно не знаю, как мне реализовать, чтобы собрать все предметы из 64 URL-адресов и в конечном итоге превратить их в объект каталог (он содержит список объектов-субъектов).

У меня есть прочитал много статей и сообщений об асинхронной и синхронной обработке, это меня так сбивает с толку. Я был бы очень признателен за простой и понятный код, который поможет мне решить эту проблему. Спасибо, ребята!

let urlBook = getUrlFromBook()

func fetchClassInfo(url:URL,completion: @escaping ([clase])-> Void){
    let task = URLSession.shared.dataTask(with: url){(data, response, error) in
        let jsonDecoder = JSONDecoder()
        if let data = data,
            let collection:[clase] = try?  jsonDecoder.decode([clase].self, from: data){
            completion(collection)
        }else{
            print("Either no data was returned, or data was not properly decoded.")
            //completion(nil)
        }
    }
    task.resume()
}

fetchClassInfo(url:urlBook.book[0]){(clase) in
    let newSubject = makeNewSubject(subjectIndex: 0, collectionOfCourse: clase)
    var masterCatalog = catalog(subjectCollection: [])
     masterCatalog.addSubject(newSubject: newSubject)

    }

Ответы [ 3 ]

1 голос
/ 18 июня 2020

Вы можете создать логи c, как показано ниже. Эта функция принимает список URL-адресов и возвращает завершенный список Subject. Вы можете модифицировать модели et c, как вам нужно. В этой функции; DispatchGroup - дождаться завершения всех запросов перед вызовом completion, а DispatchQueue - предотвращать «гонку данных» при добавлении объектов в массив.

func downloadUrls(urls: [URL], completion: @escaping ([Subject]) -> Void) {
    var subjectCollection: [Subject] = []    
    let urlDownloadQueue = DispatchQueue(label: "com.urlDownloader.urlqueue")
    let urlDownloadGroup = DispatchGroup()

    urls.forEach { (url) in
        urlDownloadGroup.enter()

        URLSession.shared.dataTask(with: url, completionHandler: { (data, response, error) in
            guard let data = data, 
                let subject = try? JSONDecoder().decode(Subject.self, from: data) else {                    
                // handle error                    
                urlDownloadQueue.async {
                    urlDownloadGroup.leave()
                }
                return
            }

            urlDownloadQueue.async {
                subjectCollection.append(subject)
                urlDownloadGroup.leave()
            }
        })
    }

    urlDownloadGroup.notify(queue: DispatchQueue.global()) {
        completion(subjectCollection)
    }
}
1 голос
/ 18 июня 2020

Я бы посоветовал взглянуть на подход Promises, так как он предлагает решения для асинхронных задач из коробки. Есть много реализаций Promises на swift. Более того, вы можете попробовать использовать среду SDK Combine, но она немного сложна и работает только с iOS 13.

Например, есть образец с моим PromiseQ swift пакетом:

Promise.all( paths.map { fetch($0) } ) // Download all paths concurrently
.then { dataArray in
    // Parse all data to array of results
    let results:[YourClass] = dataArray.compactMap { try? JSONDecoder().decode(YourClass.self, from: $0) }
}

Где:

  • paths:[String] - массив с http-путями для загрузки.
  • fetch(_ path: String) -> Promise<Data> - специальная функция для загрузки данных по пути который возвращает обещание.
  • YourClass - ваш класс для синтаксического анализа.
1 голос
/ 18 июня 2020

Это функция, которая загружает все URL-адреса одновременно:

func downloadAllUrls(urls: [String]){
    let dispatchGroup = DispatchGroup()
    for url in urls {
        dispatchGroup.enter()
        // Here is where you have to do your get call to server 
        // and when finished call dispatchGroup.leave()
    }
    dispatchGroup.notify(queue: .main) {
        // Do what ever you want after all calls are finished
    }
}

она использует DispatchQueue для уведомления о завершении всех запросов, а затем вы можете делать с ними все, что захотите. Сервер может быть вашим настраиваемым асинхронным c вызовом в сеть. У меня такая же.

...