8

I'm using Alamofire to do a POST request. As this POST request can take a while and I want to keep track of the progress and display it as a ProgressView.

Alamofire.request(.POST, ApiLink.create_post, parameters: parameters, encoding: .JSON)
        .progress { (bytesRead, totalBytesRead, totalBytesExpectedToRead) -> Void in
            println("ENTER .PROGRESSS")
            println("\(totalBytesRead) of \(totalBytesExpectedToRead)")                
            self.progressView.setProgress(Float(totalBytesRead) / Float(totalBytesExpectedToRead), animated: true)
        }
        .responseJSON { (_, _, mydata, _) in 
            println(mydata)
        }

However, I've noticed that the .progress block only get called after the post request has ended instead of getting called multiple times to actually keep track of the progress. println("ENTER .PROGRESSS") gets called only once (at the end)

How can I make .progress works with Alamofire.request POST ?

Also : My parameters include a base64 encoded image string. I'm using a back-end Ruby on Rails to process the image. It's that process that is taking quite some time.

fabdarice
  • 885
  • 2
  • 11
  • 23
  • If it's just JSON you're getting back, it could very well be that the entire payload is coming back all at once... What exactly is being printed out? – mattt Feb 03 '15 at 00:08
  • Oh yeah I'm indeed getting a simple JSON request after it comes back. The thing is that my parameters include an image base64 encoded. I'm using a back-end Rails to process the uploaded image and this is this process that takes some time. – fabdarice Feb 03 '15 at 00:31
  • Unless you're doing `upload`, the progress reported is the download progress. – mattt Feb 03 '15 at 21:27
  • would you be able to tell me the difference between doing .upload (passing a NSData Image) or doing a simple .POST request with a base64 encoded image string? – fabdarice Feb 03 '15 at 21:32

3 Answers3

7

What you can do instead is first use the ParameterEncoding enum to generate the HTTPBody data. Then you can pull that data out and pass it off to the Alamofire upload method. Here's a modified version of your same function that compiles in a playground and instead uses the upload function.

struct ApiLink {
    static let create_post = "/my/path/for/create/post"
}

let parameters: [String: AnyObject] = ["key": "value"] // Make sure this has your image as well

let mutableURLRequest = NSMutableURLRequest(URL: NSURL(string: ApiLink.create_post)!)
mutableURLRequest.HTTPMethod = Method.POST.rawValue

let encodedURLRequest = ParameterEncoding.JSON.encode(mutableURLRequest, parameters: parameters).0
let data = encodedURLRequest.HTTPBody!

let progressView = UIProgressView()

Alamofire.upload(mutableURLRequest, data)
         .progress { _, totalBytesRead, totalBytesExpectedToRead in
             println("ENTER .PROGRESSS")
             println("\(totalBytesRead) of \(totalBytesExpectedToRead)")
             progressView.setProgress(Float(totalBytesRead) / Float(totalBytesExpectedToRead), animated: true)
         }
         .responseJSON { _, _, mydata, _ in
             println(mydata)
         }

This will certainly have progress updates as @mattt originally mentioned in his comment above.

cnoon
  • 16,575
  • 7
  • 58
  • 66
  • How do I retrieve the parameters in the back-end with .upload? I'm using a rails as my back-end and all the parameters I retrieve with .request are now nil with .upload. – fabdarice Feb 10 '15 at 02:24
  • You probably need to package the data as a MultipartFormData object before uploading it. Until Alamofire has support for MultipartFormData uploads, you will need to use [AFNetworking](https://github.com/AFNetworking/AFNetworking). You could also pass the parameters in the URL and pass the data in the `HTTPBody`. It depends on what your server expects. – cnoon Feb 10 '15 at 05:34
  • Hi @fabdarice, if this answer helped you solve your problem, could you mark it as such to be a good community user? Cheers. – cnoon Mar 08 '15 at 17:32
  • Does this upload overload still exist? – Ian Warburton May 25 '17 at 14:13
1

As @cnoon said you can use upload method to track progress with some modifications. Here is what exactly worked with me:

let jsonData = NSJSONSerialization.dataWithJSONObject(jsonObject, options: .PrettyPrinted)
Alamofire.upload(.POST, "API URL String", headers: ["Content-Type": "application/json"], data: jsonData)
         .validate()
         .responseJSON(completionHandler: { (response: Response<AnyObject, NSError>) in
             //Completion handler code
         })
         .progress({ (bytesWritten: Int64, totalBytesWritten: Int64, totalBytesExpectedToWrite: Int64) in
             //Progress handler code
         })

Note that you must set the "Content-Type" http header field value to "application/json" if the data is formatted as json to be decoded correctly at the backend.

Basem Saadawy
  • 1,808
  • 2
  • 20
  • 30
0

There's a separate method in Alamofire to upload. Please check their documentation here.

They have sub-sections

  1. Uploading with Progress
  2. Uploading MultipartFormData

Which describes uploading.

Ruchira Randana
  • 4,021
  • 1
  • 27
  • 24