10

I have used Alamofire for uploading images in multipart form data. I am successful in achieving my target. Each time I upload an image, I call the "uploadDocWebService" function. So the number of times the function is called, is equal to the number of images. I am hopeless in identifying the result of each call. My images are uploaded successfully. In case there is a server failure, or internet connection failure the uploading fails, I cannot identify which image I should delete from the view, that has failed. I pass indexPath as a parameter for each image upload. But that indexPath updates to the latest image upload before I receive the result for the first image upload. Can any one suggest me a better approach for this situation.

Here is the code I use for image upload:

func uploadDocWebservice(fileUrl: NSURL , progressView : PWProgressView , index : String , imageData : NSData? , name : String , mimeType : String , uploadType : String){

    let url = "\(kBaseURL)\(uploadDocsUrl)"

    var type = String()
    var networkGroupId = String(SingletonClass.sharedInstance.selectedNetworkId!)

    if SingletonClass.sharedInstance.groupPopUp == true {

        type = "group"
        networkGroupId = String(SingletonClass.sharedInstance.selectedSubNetworkOrGroup!)

    }else {

        type = "network"
    }

    Alamofire.upload(
        .POST,
        url,
        multipartFormData: { multipartFormData in

            if uploadType == "Image" {
                multipartFormData.appendBodyPart( data: imageData! , name: "file", fileName: name, mimeType: mimeType)
            }else {
                multipartFormData.appendBodyPart(fileURL: fileUrl, name: "file")
            }
            multipartFormData.appendBodyPart(data:"\(SingletonClass.sharedInstance.tokenId)".dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)!, name :"token")
            multipartFormData.appendBodyPart(data:"\(type)".dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)!, name :"networkGroup")
            multipartFormData.appendBodyPart(data:"\(networkGroupId)".dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)!, name :"networkGroupId")

        },
        encodingCompletion: { encodingResult in
            switch encodingResult {
            case .Success(let upload, _, _):

                upload.progress { bytesRead, totalBytesRead, totalBytesExpectedToRead in

                    let ratio: Float = Float(totalBytesRead) / Float(totalBytesExpectedToRead)
                    // Call main thread.
                    dispatch_async(dispatch_get_main_queue(), {
                        progressView.progress = ratio
                    })

                }

                upload.responseJSON { response in

                    let dataString = NSString(data: response.data!, encoding:NSUTF8StringEncoding)
                    print(dataString)

                    self.edited = true

                    do{

                        let json = try NSJSONSerialization.JSONObjectWithData(response.data!, options: .MutableLeaves) as? NSDictionary

                        if let success = json!["success"] as? Int {

                            if success == 1 {

                                let id = json!["response"]!.objectForKey("id") as! String
                                let docName = "\(json!["response"]!.objectForKey("name") as! String).\(json!["response"]!.objectForKey("ext") as! String)"
                                let dic = ["name" : docName , "Id" : id]
                                self.uploadedDocsIdArray.addObject(dic)
                                self.uploadedArrayJustNames.addObject(docName)
                                print(self.uploadedDocsIdArray)

                            }else {

                                // delete image from view here

                            }

                        }

                    }catch{

                        // delete image from view here
                        invokeAlertMethod("Error", msgBody: "Invalid Json", delegate: self)

                    }

                }
            case .Failure(let encodingError):

                print(encodingError)
            }
        }
    )

}

If I get to know the which result is associated to which call, that could help me delete that particular image from view.

Amrit Sidhu
  • 1,870
  • 1
  • 18
  • 32
  • You need to have unique id for each image OR something which is uniquely associated with each image. For example, you can have a separate upload tracking dictionary containing image-Ids as keys and its value as a Bool. Initially all values will be "false". Whenever upload is successful for an image-Id you can set that value to "true". – san Feb 02 '16 at 06:21
  • I have already tried this. In case there is a connection or server failure I will not be returned the image id that is failed. Failed images can be more than one. – Amrit Sidhu Feb 02 '16 at 06:38
  • Do you get image-Id for successful upload ? – san Feb 02 '16 at 06:48
  • Yes I do get that for successful uploads – Amrit Sidhu Feb 02 '16 at 07:01
  • Then, you can set that value against that image-id to true and remove the image(from view) associated with that id. I think I am not able to understand your problem completely. Sorry. – san Feb 02 '16 at 07:10
  • I donot want to remove the image in case of success. The image needs to be removed only in case of failure. – Amrit Sidhu Feb 02 '16 at 07:20
  • You can check for the inverted set then - let's say you know you have image ids [123, 456, 789], you know 123 and 789 are successful, so the one missing is 456 and thus must be deleted. – Drmorgan Mar 29 '16 at 18:23
  • @Drmorgan : I tried this case also. But is there any hope we can get a reference to the call. For example : If I call the request for the first time, the request should be tagged as first request. All requests should be tagged . Is there any such solution?? – Amrit Sidhu Mar 30 '16 at 04:01
  • 3
    @AmritSidhu you mentioned previously that you get the image-id for successful uploads. If that is still true you don't need to tag the requests - as soon as you receive the success you will know which ones succeeded. Then once all requests are complete you can check to see which are missing from the set/array of successful image downloads. To check when multiple requests are complete, I would checkout `dispatch_group` to be notified when a group of tasks are complete. RayWenderlich has a great example of dispatch groups https://www.raywenderlich.com/63338/grand-central-dispatch-in-depth-part-2 – Drmorgan Mar 30 '16 at 14:40
  • I will that a simple `completionHandler` closure would do the trick. The caller always has enough context and you can persist the context in the completion handler. – Sulthan Apr 02 '16 at 11:39

1 Answers1

3

You need to keep a reference to the original request, should be the same for upload requests I think. Try the following:

func uploadDocWebservice(fileUrl: NSURL , progressView : PWProgressView , index : String , imageData : NSData? , name : String , mimeType : String , uploadType : String) -> Request? {
    return Alamofire.upload ...
}

Then you can simply have an array of requests i.e: var requests: [Request](). When calling Alamofire.upload / Alamofire .request - it returns a Request object.

You can then do:

var requests: [Request]()
let request = uploadDocWebservice(...)
requests.append(request)

Then you can just loop through the array and check whatever request you wish.

Nagra
  • 1,529
  • 3
  • 15
  • 25