Swift 3 Alamofire multipart upload

29,890

Solution 1

For example, using Alamofire 4.0.0 in Swift 3:

(make sure you are 4.0.0 ready as it looks like you haven't updated your Alamofire yet)

Alamofire.upload(multipartFormData: { (multipartFormData) in
        // code
    }, to: URL, encodingCompletion: { (result) in
        // code
    })

or

Alamofire.upload(multipartFormData: { (multipartFormData) in
        // code
    }, with: URL, encodingCompletion: { (result) in
        // code
    })

So headers need to be passed by URL request:

let URL = try! URLRequest(url: "http://example.com", method: .get, headers: headers)

Solution 2

Try this one and url set as @pedrouan said.

Alamofire.upload(multipartFormData: { (multipartFormData) in
       multipartFormData.append(imageData, withName: "xyz", fileName: "file.jpeg", mimeType: "image/jpeg")
}, to: url) 
{ (result) in
      //result
}

Solution 3

For Swift 3 and Alamofire ~4.3.0

If someone like me tried to get request object synchronously (without using locks or dispatch_groups) you can use this approach:

// outer function
...
let string = "string to send"
let multipartFormData = MultipartFormData()
multipartFormData.append(string.data(using: .utf8)!, withName: "str")

guard let data = try? multipartFormData.encode() else {
    // fail appropriately
}

let request = sessionManager.upload(data,
                                    to: url,
                                    method: .post,
/* this is VERY IMPORTANT LINE */   headers: ["Content-Type" : multipartFormData.contentType])

request.validate()
// do whatever you need with request

Please note that you need to set Content-Type header from you multipartFormData as it contains boundaries.

If you don't need to have your request object synchronously the other answer with

Alamofire.upload(multipartFormData: { (multipartFormData) in

is working as expected. In case of successful encoding of data it will return you request object in callback closure.

IMPORTANT NOTE: if you use the method I have described, it will block your thread (in most cases you probably are in Main thread) to copy and encode your data. So don't use it for large files or whatever. It is async in Alamofire on purpose.

Solution 4

In swift 3, trying to set multipartFormData as @DCDC pointed out in his solution. XCode try to cast to AnyObject before .data(), so instead of

value.data(using: String.Encoding.utf8)!, withName: key

I did

[replace_your_var_name_here].data(using: String.Encoding.utf8)!, withName: key

In my case my var list was not big so hardcoding was an option.

Share:
29,890

Related videos on Youtube

theDC
Author by

theDC

iOS dev and cofounder at codepany.com

Updated on February 15, 2020

Comments

  • theDC
    theDC about 4 years

    Thanks to migration to Swift 3, I find it difficult to compile my project that uses Alamofire.

    The problem occurs when uploading multipartFormData:

    Alamofire.upload(.POST, URL, headers: headers, multipartFormData: {
            multipartFormData in
    .
    .
    . 
    }) 
    

    Ambiguous reference to member 'upload(_:to:method:headers:)'

    Any help much appreciated, thanks in advance!

    RESOLVED:

     Alamofire.upload(multipartFormData: { (multipartFormData) in
    
            multipartFormData.append(fileData, withName: "file_pack", fileName: "file_pack", mimeType: "text/plain")
    
    
            for (key, value) in self.parameters {
                multipartFormData.append(value.data(using: String.Encoding.utf8)!, withName: key)
            }
            }, with: URL2, encodingCompletion: { (result) in
    
                switch result {
                case .success(let upload, _, _):
    
                    upload.responseJSON { response in
                        self.delegate?.showSuccessAlert()
                        print(response.request)  // original URL request
                        print(response.response) // URL response
                        print(response.data)     // server data
                        print(response.result)   // result of response serialization
                        //                        self.showSuccesAlert()
                        self.removeImage("frame", fileExtension: "txt")
                        if let JSON = response.result.value {
                            print("JSON: \(JSON)")
                        }
                    }
    
                case .failure(let encodingError):
                    self.delegate?.showFailAlert()
                    print(encodingError)
                }
    
        })
    

    This is how upload method should be implemented in Swift 3

    • Eric Aya
      Eric Aya over 7 years
      The method signatures have changed. Comment your existing ones and let Xcode's autocomplete guide you for writing the new ones.
    • Sahil
      Sahil over 7 years
      and you can also go to alamofire on gitub. github.com/Alamofire/Alamofire
  • theDC
    theDC over 7 years
    one more question, what code should go in first placeholder(multipartFormData in) and what should go in the latter (result in)? Formerly there was only one closure
  • pedrouan
    pedrouan over 7 years
    It is not mandatory to fill it with code, closures are for you eventual use. But I guess, completion closures are useful as you get feedback since it's asynchronous method.
  • theDC
    theDC over 7 years
  • pedrouan
    pedrouan over 7 years
    @DCDC It looks like your Alamofire has not been updated to 4.0.0
  • theDC
    theDC over 7 years
    Well it is, otherwise it would nit show the first error message I guess
  • pedrouan
    pedrouan over 7 years
    Yes -and, if you want to migrate to Swift 3.0, upgrading Alamofire to 4 version is a must. Now I guess you would get that by yourself, if it is from 4. Anyway, if you need some assistance and/or create another question any time, comment me and I'll check it.
  • theDC
    theDC over 7 years
    Ok, it doesn't return any errors now, the problem was with my method implementation, see my edited question. Thanks!
  • Gregg
    Gregg over 7 years
    This still doesn't work for me..... anybody else? Not sure what else to do.
  • Saeid
    Saeid over 7 years
    how about audio file? - i try to send a audio file in this form : multipartFormData.append(audioLocalPath, withName: "file", fileName: "file", mimeType: "application/octet-stream") but occur this error : multipartEncodingFailed(Alamofire.AFError.MultipartEncodingF‌​ailureReason.bodyPar‌​tFileNotReachableWit‌​hError(file:///var/m‌​obile/Containers/...‌​.... /Documents/item.mp3, NSUnderlyingError=0x16049100 {Error Domain=NSPOSIXErrorDomain Code=2 "No such file or directory"}})) - where is problem? -bad request or bad audio path?
  • Bilawal Liaqat
    Bilawal Liaqat about 7 years
    @pedrouan Thank you man . I was looking for this from last 5 hours. and there was many solution available but this one work only
  • Arbitur
    Arbitur almost 7 years
    Where is sessionManager comming from?
  • user1264176
    user1264176 almost 7 years
    @Arbitur it is an instance of Alamofire.SessionManager you use to make a request. In my production code it is created once when app is initialised and used throughout the app. In this particular snippet from the answer it can be created in the code marked as '...' after //outer function. Although again, it is not relevant where you have created your session manager for this snippet.
  • Aashish
    Aashish over 6 years
    using the urlRequest gives error <"Type of expression is ambiguous without more content" >, but works if only used url. What am i missing??