swift3 - 同步发送多个 URLSession dataTask 请求并等待结束
问题描述
我需要向我的服务器发送多个 POST 请求,但是在执行此操作时遇到了同步问题。
我需要执行以下操作:
- 显示进度条(下载中...)
- 发送第一个 POST 请求
- 每发送n张图片
- 发送图片 n
- 结束
发送每个帖子时,禁用进度条显示状态弹出消息
这是我使用的代码:
调用第一个 POST 请求的函数
self.envoi{ (response) in if let result = response as? Bool { if(result == true){ //now we are sending the Photos ! var i = 0; while(i < selectedPictures.sharedInstance.selectedCells.count){ self.envoiPhoto(obj: PhotoGallery.sharedInstance.photoGallery[item], pic: self.Image, num: item){ (result) -> () in print("Envoi Photo \(i): \(result)") } i=i+1; }//end loop while for each pic print("we have sent all the pictures") alertController.dismiss(animated: true, completion: ({ })) self.envoiSuccess() } else{ print("erreur d'envoi") self.envoiError() } } }
第一个 func envoi:
func envoi(_ callback: @escaping (Bool) -> ()){
let url = URL(string: "\(SERVER)/MobileCreate")
var request = URLRequest(url: url!)
request.httpMethod = "POST"
let boundary = generateBoundaryString()
request.setValue("multipart/form-data; boundary=\(boundary)", forHTTPHeaderField: "Content-Type")
let body = NSMutableData()
let CRLF = "\r\n";
//send parameter id_user
body.append("--\(boundary)\(CRLF)".data(using: String.Encoding.utf8)!)
body.append("Content-Disposition: form-data; name=\"id_user\"\(CRLF)".data(using: String.Encoding.utf8)!)
body.append("Content-Type: text/plain; charset=UTF-8\(CRLF)\(CRLF)".data(using: String.Encoding.utf8)!)
body.append("\(User.sharedInstance.id!)\(CRLF)".data(using: String.Encoding.utf8)!)
//send parameters reference
body.append("--\(boundary)\(CRLF)".data(using: String.Encoding.utf8)!)
body.append("Content-Disposition: form-data; name=\"reference\"\(CRLF)".data(using: String.Encoding.utf8)!)
body.append("Content-Type: text/plain; charset=UTF-8\(CRLF)\(CRLF)".data(using: String.Encoding.utf8)!)
body.append("\(ref.text!)\(CRLF)".data(using: String.Encoding.utf8)!)
body.append("\(CRLF)".data(using: String.Encoding.utf8)!)
body.append("--\(boundary)--\(CRLF)".data(using: String.Encoding.utf8)!)
request.httpBody = body as Data
let configuration = URLSessionConfiguration.default
let session = Foundation.URLSession(configuration: configuration,
delegate: self,
delegateQueue:OperationQueue.main)
let task = session.dataTask(with: request, completionHandler: {
(data, response, error) in
guard let _:Data = data, let _:URLResponse = response, error == nil else {
print("error")
callback(false)
return
}
var id = "0";
var result = "";
if let response = response as? HTTPURLResponse {
if response.statusCode == 200 {
print("Create Success")
}
id = response.allHeaderFields["id"]! as! String
result = response.allHeaderFields["result"]! as! String;
print("Result: \(result)");
callback(true)
}
})
task.resume()
}
第二个功能 envoiPhoto:
func envoiPhoto(obj: Photo, pic: UIImage, num: Int, completion: @escaping (_ result: Bool)->()){
let url = URL(string: "\(KAIROS_SERVER)/MobileCreatePhoto")
var request = URLRequest(url: url!)
request.httpMethod = "POST"
let boundary = self.generateBoundaryString()
request.setValue("multipart/form-data; boundary=\(boundary)", forHTTPHeaderField: "Content-Type")
let image_data = UIImagePNGRepresentation(self.fixOrientation(img: self.constatImage))
let body = NSMutableData()
//preparing values for pictures
let fname = "Constat-\(reference!)-\(num).png"
let mimetype = "image/png"
let CRLF = "\r\n";
//send parameter id
body.append("--\(boundary)\(CRLF)".data(using: String.Encoding.utf8)!)
body.append("Content-Disposition: form-data; name=\"id\"\(CRLF)".data(using: String.Encoding.utf8)!)
body.append("Content-Type: text/plain; charset=UTF-8\(CRLF)\(CRLF)".data(using: String.Encoding.utf8)!)
body.append("\(id!)\(CRLF)".data(using: String.Encoding.utf8)!)
body.append("--\(boundary)\(CRLF)".data(using: String.Encoding.utf8)!)
body.append("Content-Disposition: form-data; name=\"file\"; filename=\"\(fname)\"\(CRLF)".data(using: String.Encoding.utf8)!)
body.append("Content-Type: \(mimetype)\(CRLF)\(CRLF)".data(using: String.Encoding.utf8)!)
body.append(image_data!)
body.append("\(CRLF)".data(using: String.Encoding.utf8)!)
body.append("--\(boundary)--\(CRLF)".data(using: String.Encoding.utf8)!)
request.httpBody = body as Data
let configuration = URLSessionConfiguration.default
let session = Foundation.URLSession(configuration: configuration,
delegate: self,
delegateQueue:OperationQueue.main)
let task = session.dataTask(with: request, completionHandler: {
(
data, response, error) in
guard let _:Data = data, let _:URLResponse = response, error == nil else {
print("error")
completion(false)
return
}
var id = "0";
var result = "";
// Print out response string
//print("response -- \(response)")
if let response = response as? HTTPURLResponse {
if response.statusCode == 200 {
print("Create Photo Success")
}
id = response.allHeaderFields["id"]! as! String
print("ID Photo created: \(id)");
result = response.allHeaderFields["result"]! as! String;
print("Result: \(result)");
}
completion(true)
})
task.resume()
}
我今天主要关心的是确保在向最终用户显示进度条的同时同步发送每个 HTTP POST。当第一个 HTTP POST 和每个发送图片的 HTTP POST 完成时,我需要禁用进度条并显示另一个 alertView 详细说明操作。
截至今天,操作尚未同步,即使操作未完成,代码也会尝试禁用进度条。照片上传的启动是在第一个 HTTP POST 之后开始的(因为它在回调中开始)但是因为我需要为要发送的每张图片实现一个循环我不知道如何在不阻塞 URLSession 数据的情况下同步每次上传任务(如果我使用 DispatchGroup 就是这种情况)
任何帮助将不胜感激 !
-------------------------------------------------- ------------------------ 编辑 1
我试图在我的代码中实现 DispatchGroup 但没有按预期同步...
这是代码:
var myGroup = DispatchGroup();
self.docSent = false;
self.allPhotosSent = false
self.myGroup.enter()
print("First sending the doc")
self.envoi{ (response) in
if let result = response as? Bool {
if(result == true){
self.docSent = true
print("Doc sent, now sending photos")
//now we are sending the Photos !
for it in selectedPictures.sharedInstance.selectedCells{
print("Sending selected pic item:\(it.item)");
print("retrieving picture: \(fileName!)")
self.constatImage = self.getSavedImage(named: fileName!)!
self.envoiPhoto(obj: PhotoGallery.sharedInstance.photoGallery[it.item], pic: self.Image, num: it.item){ (result) -> () in
print("Envoi Photo \(it.item): \(result)")
if(it.item == selectedPictures.sharedInstance.selectedCells.count-1){
self.allPhotosSent = true
}
}
}
}
//Case when doc sending is failed
else{
self.docSent = false
}
}
}//end envoi doc
self.myGroup.leave()
self.myGroup.notify(queue: .main, execute: {
print("entering in notify")
print("we have sent all the pictures")
if(self.docSent && self.allPhotosSent){
//now we need to leave the progress bar...
alertController.dismiss(animated: true, completion: ({
print("now the alert is dismissed !")
self.envoiSuccess()
}))
}
else{
print("erreur d'envoi de doc")
alertController.dismiss(animated: true, completion: ({
print("now the alert is dismissed !")
self.envoiError()
}))
}
})
和日志:
First sending the doc
entering in notify
we have sent all the pictures
erreur d'envoi de doc
Result: success
doc sent, now sending photos
Sending selected pic item:0
retrieving picture: IMG_0241
Sending selected pic item:1
retrieving picture: IMG_1265
now the alert is dismissed !
Result: success
Envoi Photo 0: true
Result: success
Envoi Photo 1: true
当然,我错过了一些东西,因为 GCD 似乎没有像我预期的那样工作。
解决方案
推荐阅读
- wso2 - 带有鉴别器的 WSO2 身份服务器用户名
- php - 在正则表达式匹配后获取上一个和下一个 10 个单词
- java - 按钮的边距未在 Android 中以编程方式设置
- java - 在 @PostConstruct 中调用另一个 bean 的方法引发了一个空指针 ex
- java - Java, sqlite3 自命令行故障排除
- kubernetes - 有没有办法在 K8S 单节点部署多容器应用程序进行生产?
- excel - 如何在Excel VBA中将字符#更改为=
- android - 如何频繁地从 api 获取数据?
- sql - 有没有办法使用 sqoop 将所有表而不是视图从 RDBMS 导入配置单元
- android - 插入或更新操作时如何显示 SQLException