>我正在尝试从学校课程目录站点下载数据。我在变量 UrlBook 中有 64 个 Url。我已经成功地编写了代码来下载课程集合,并使用完成处理程序方法将它们从单个 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)
}
你基本上可以创建一个如下逻辑。此函数获取 url 列表,并在完成时返回主题列表。您可以根据需要修改模型等。在此功能中;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()
}
}).resume()
}
urlDownloadGroup.notify(queue: DispatchQueue.global()) {
completion(subjectCollection)
}
}
这是一个同时下载所有 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 在所有请求完成时发出通知,然后您可以对它们执行任何您想要的操作。服务器可以是您对网络的自定义异步调用。我的就是这样。
我建议查看Promises方法,因为它具有开箱即用的异步任务解决方案。在 swift 上有许多 Promise 的实现。你可以尝试使用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
- 要解析的类。