0

I would need to send multiple POST requests to my server but I'm encountering a problem of synchronization while doing it.

I would need to do the following:

  • display progress bar (download in progress...)
  • send the first POST request
  • for each n pictures to be sent
    • send picture n
  • end for

when every post are sent, disable progress bar display status popup message

here is the code I used:

  • the func calling the first POST request

    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()
    }
    }
    }
    

the first 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()
}

the second func 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() 
}

my main concern today is to ensure that each HTTP POST are sent synchronously while a progress bar is displayed to the end user. when the first HTTP POST and each HTTP POST to send pictures are finished, I would need to disable the progress bar and display another alertView detailing the operation.

As of today, the operations are not synced and the code is trying to disable the progress bar even if operations are not finished. The startup of photo upload is starting after the first HTTP POST (as it starts in the callback) but as I need to implement a loop for each respective picture to be sent I don't know how to synchronize each upload without blocking the URLSession data task (which is the case If I'm using DispatchGroup)

any help will be appreciated !

------------------------------------------------------------------------- EDIT 1

I tried to implement DispatchGroup in my code but nothing is synchronized as expected...

Here is the code:

            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()
                }))
            }

        })

and the logs:

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

For sure I missed something as it seems that GCD is not working as I'm expecting.

tiamat
  • 879
  • 2
  • 12
  • 35

0 Answers0