Swift iOS -UrlSession 移动非常慢。有没有办法同时执行多个任务?

Swift iOS -UrlSession moving very slow. Is there a way to do multiple tasks at once?

我有 url 数组,数组中可以有 1 到 6 张图片,最多只能有 1 到 6 张。

我正在使用的当前循环现在可以正常工作,但 UrlSession 的移动速度慢得离谱。将 6 张图片上传到 Firebase 大约需要 1-2 分钟。我已经用 while 运行ning Xcode 和 while not 运行ning Xcode 试过了,不管它移动得多么慢。我的网络很快所以不是那样。

我读过多个 SO 帖子,它们说关键是将 completionHandler 放在主队列上,这是我尝试过但无济于事的方法。

有没有一种方法可以同时执行多个 UrlSession 而不是循环执行它们?

这行得通,但移动速度很慢wwwwww:

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,但我想不出一种方法来知道它们何时完成所以我可以 运行 我的 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:

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,配置和存储(即不是共享会话) ,用于所有不同的任务。会话将能够安排这些并减少您的延迟。