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

标签 ios swift switch-statement grand-central-dispatch nsurlsession

我有一个 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/

相关文章:

ios - 在展开 segue 之前显示 UIAlert

ios - 字符串到 int 的转换不能快速工作

javascript - 简化 JavaScript 中的迭代 if/else if 语句

Java Switch 语句 - "or"/"and"可能吗?

javascript - 如何在 JavaScript 中对数组进行 switch() ?

ios - 使用 openssl 的 RSA 加密,使用 PKCS1 填充的加密文本的可变长度

ios - 使容器 View 的 viewController 大于容器 View 的大小。可能的?

带有身份验证 API key 的 Swift 4 URLsession

ios - 如何排除模型自身的阴影?

iphone - 使用 cocos2D 的 Endless Game 背景的视差滚动