我有一个 url 数组,数组内可以有 1 到 6 个图像,最多只能有这个。
我正在使用的当前循环现在可以工作,但 UrlSession 的移动速度慢得离谱。将 6 张图片上传到 Firebase 大约需要 1-2 分钟。我在运行 Xcode 时和不运行 Xcode 时都尝试过,无论什么它移动都很慢。我的网络很快,所以不是这样。
我读过多篇SO帖子,其中说关键是将completionHandler放在主队列上,但我尝试过但没有成功。
有没有办法可以一次执行多个 UrlSession,而不是循环遍历它们?
这可行,但移动速度慢wwww:
var urls = [URL]()
picUUID = UUID().uuidString
dict = [String:Any]()
let myGroup = DispatchGroup()
var count = 0
for url in urls{
myGroup.enter() // enter group here
URLSession.shared.dataTask(with: url!, completionHandler: {
(data, response, error) in
guard let data = data, let _ = error else { return }
DispatchQueue.main.async{
self.firstLoopUrlsToSendDataToStorage("\(self.picUUID)_\(self.count).jpg", picData: data)
self.count += 1
}
}).resume()
// send dictionary data to firebase when loop is done
myGroup.notify(queue: .global(qos: .background)) {
self.secondWhenLoopIsFinishedSendDictToFirebaseDatabase()
self.count = 0
}
}
func firstLoopUrlsToSendDataToStorage(_ picId: String, picData: Data?){
dict.updateValue(picId, forKey:"picId_\(count)")
let picRef = storageRoot.child("pics")
picRef.putData(picData!, metadata: nil, completion: { (metadata, error) in
if let picUrl = metadata?.downloadURL()?.absoluteString{
self.dict.updateValue(picUrl, forKey:"picUrl_\(count)")
self.myGroup.leave() // leave group here
}else{
self.myGroup.leave() // leave group if picUrl is nil
}
}
}
func secondWhenLoopIsFinishedSendDictToFirebaseDatabase(){
let ref = dbRoot.child("myRef")
ref.updateChildValues(dict, withCompletionBlock: { (error, ref) in
DispatchQueue.main.async{
self.displaySuccessAlert()
}
}
}
我看了这个guy's Medium post并且考虑将其与 switch 语句结合起来,因为只能有 1-6 个 url,但我无法找到一种方法来知道所有这些 url 何时完成,以便我可以运行我的 secondWhenLoopIsFinishedSendDictToFirebaseDatabase()
功能
fileprivate func multipleUsrlTaskSessionsAtOnce(){
switch userComplaintImageUrls.count {
case 0:
let urlZero = userComplaintImageUrls[0]
TaskManager.shared.dataTask(with: url) { (data, response, error) in
// how to know when all of them are completed?
}
break
case 1:
let urlOne = userComplaintImageUrls[1]
TaskManager.shared.dataTask(with: urlOne ) { (data, response, error) in
// how to know when all of them are completed?
}
break
case 2:
let urlTwo = userComplaintImageUrls[2]
TaskManager.shared.dataTask(with: urlTwo) { (data, response, error) in
// how to know when all of them are completed?
}
break
case 3:
let urlThree = userComplaintImageUrls[3]
TaskManager.shared.dataTask(with: urlThree) { (data, response, error) in
// how to know when all of them are completed?
}
break
case 4:
let urlFour = userComplaintImageUrls[4]
TaskManager.shared.dataTask(with: urlFour) { (data, response, error) in
// how to know when all of them are completed?
}
break
case 0:
let urlFive = userComplaintImageUrls[5]
TaskManager.shared.dataTask(with: urlFive) { (data, response, error) in
// how to know when all of them are completed?
}
break
default:
break
}
}
任务管理器类:
class TaskManager {
static let shared = TaskManager()
let session = URLSession(configuration: .default)
typealias completionHandler = (Data?, URLResponse?, Error?) -> Void
var tasks = [URL: [completionHandler]]()
func dataTask(with url: URL, completion: @escaping completionHandler) {
if tasks.keys.contains(url) {
tasks[url]?.append(completion)
} else {
tasks[url] = [completion]
let _ = session.dataTask(with: url, completionHandler: { [weak self] (data, response, error) in
DispatchQueue.main.async {
print("Finished network task")
guard let completionHandlers = self?.tasks[url] else { return }
for handler in completionHandlers {
print("Executing completion block")
handler(data, response, error)
}
}
}).resume()
}
}
}
最佳答案
Is there a way I can execute multiple UrlSessions all at once instead of looping through them?
恰恰相反。为了获得最佳速度,您需要配置和存储一个 URLSession(即不是共享 session ),用于您的所有不同任务。 session 将能够安排这些并减少延迟。
关于ios - Swift iOS -UrlSession 移动非常慢。有没有办法同时执行多个任务?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50442618/