首页 > 解决方案 > 同步发送多个 URLSession dataTask 请求并等待结束

问题描述

我需要向我的服务器发送多个 POST 请求,但是在执行此操作时遇到了同步问题。

我需要执行以下操作:

发送每个帖子时,禁用进度条显示状态弹出消息

这是我使用的代码:

第一个 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 似乎没有像我预期的那样工作。

标签: swift3urlsessionnsurlsessiondatatask

解决方案


推荐阅读