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