Upload image with alamofire
Solution 1
While Rob's Answer is correct, here's the Swift 2.0 version, with upload progress update.
Just Copy and Paste the following code, change the upload URL, and add in your parameters. Should work like a charm.
PS: MRProgress is an Awesome Library for progress update!
let apiToken = "ABCDE"
Alamofire.upload(
.POST,
"http://sample.com/api/upload",
multipartFormData: { multipartFormData in
multipartFormData.appendBodyPart(data: imageData, name: "yourParamName", fileName: "imageFileName.jpg", mimeType: "image/jpeg")
multipartFormData.appendBodyPart(data: apiToken.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)!, name :"api_token")
multipartFormData.appendBodyPart(data: otherBodyParamValue.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)!, name :"otherBodyParamName")
},
encodingCompletion: { encodingResult in
switch encodingResult {
case .Success(let upload, _, _):
upload.progress { (bytesWritten, totalBytesWritten, totalBytesExpectedToWrite) in
print("Uploading Avatar \(totalBytesWritten) / \(totalBytesExpectedToWrite)")
dispatch_async(dispatch_get_main_queue(),{
/**
* Update UI Thread about the progress
*/
})
}
upload.responseJSON { (JSON) in
dispatch_async(dispatch_get_main_queue(),{
//Show Alert in UI
print("Avatar uploaded");
})
}
case .Failure(let encodingError):
//Show Alert in UI
print("Avatar uploaded");
}
}
);
Solution 2
Your error is telling you that the response is not valid JSON. You're calling responseJSON
, indicating that you're expecting JSON response, but your server code isn't generating JSON. So there are two solutions:
-
I'd suggest changing your PHP code to generate JSON responses.
For example, if successful:
echo json_encode(array("success" => true, "filename" => basename($_FILES['image']['name']));
or, if not successful, perhaps:
echo json_encode(array("success" => false, "error_code" => 42, "error_msg" => 'File did not upload: '.$e - > getMessage());
Clearly, you have to remove the extraneous
echo
lines in the PHP if you're going to return JSON, but hopefully this illustrates the pattern. But this will generate a response that you can parse with Alamofire'sresponseJSON
(or useNSJSONSerialization
). Alternatively, you could change the Alamofire code to not expect JSON (e.g. call
response
rather thanresponseJSON
), but then parsing the responses becomes far more difficult.
As a minor, unrelated issue, I'd personally advise not building that request manually, but rather let Alamofire do that for you. Here's an example from the README:
Alamofire.upload(
multipartFormData: { multipartFormData in
multipartFormData.append(unicornImageURL, withName: "unicorn")
multipartFormData.append(rainbowImageURL, withName: "rainbow")
},
to: "https://httpbin.org/post",
encodingCompletion: { encodingResult in
switch encodingResult {
case .success(let upload, _, _):
upload.responseJSON { response in
debugPrint(response)
}
case .failure(let encodingError):
print(encodingError)
}
}
)
This is for Swift 3 and Alamofire 4. See revision history for this question for prior versions.
user3087360
Updated on June 26, 2020Comments
-
user3087360 almost 4 years
I'm trying to upload an image to server with Alamofire but my code doesn't work. This is my code:
var parameters = ["image": "1.jpg"] let image = UIImage(named: "1.jpg") let imageData = UIImagePNGRepresentation(image) let urlRequest = urlRequestWithComponents("http://tranthanhphongcntt.esy.es/task_manager/IOSFileUpload/", parameters: parameters, imageData: imageData) Alamofire.upload(urlRequest.0, data: urlRequest.1) .progress { (bytesWritten, totalBytesWritten, totalBytesExpectedToWrite) in println("\(totalBytesWritten) / \(totalBytesExpectedToWrite)") } .responseJSON { (request, response, JSON, error) in println("REQUEST \(request)") println("RESPONSE \(response)") println("JSON \(JSON)") println("ERROR \(error)") }
and this is urlRequestWithComponents methos:
func urlRequestWithComponents(urlString:String, parameters:Dictionary<String, String>, imageData:NSData) -> (URLRequestConvertible, NSData) { // create url request to send var mutableURLRequest = NSMutableURLRequest(URL: NSURL(string: urlString)!) mutableURLRequest.HTTPMethod = Alamofire.Method.POST.rawValue let boundaryConstant = "myRandomBoundary12345"; let contentType = "multipart/form-data;boundary="+boundaryConstant mutableURLRequest.setValue(contentType, forHTTPHeaderField: "Content-Type") // create upload data to send let uploadData = NSMutableData() // add image uploadData.appendData("\r\n--\(boundaryConstant)\r\n".dataUsingEncoding(NSUTF8StringEncoding)!) uploadData.appendData("Content-Disposition: form-data; name=\"file\"; filename=\"file.png\"\r\n".dataUsingEncoding(NSUTF8StringEncoding)!) uploadData.appendData("Content-Type: image/png\r\n\r\n".dataUsingEncoding(NSUTF8StringEncoding)!) uploadData.appendData(imageData) // add parameters for (key, value) in parameters { uploadData.appendData("\r\n--\(boundaryConstant)\r\n".dataUsingEncoding(NSUTF8StringEncoding)!) uploadData.appendData("Content-Disposition: form-data; name=\"\(key)\"\r\n\r\n\(value)".dataUsingEncoding(NSUTF8StringEncoding)!) } uploadData.appendData("\r\n--\(boundaryConstant)--\r\n".dataUsingEncoding(NSUTF8StringEncoding)!) // return URLRequestConvertible and NSData return (Alamofire.ParameterEncoding.URL.encode(mutableURLRequest, parameters: nil).0, uploadData) }
and this is what I get in console:
REQUEST { URL: http://tranthanhphongcntt.esy.es/task_manager/IOSFileUpload/ } RESPONSE Optional( { URL: http://tranthanhphongcntt.esy.es/task_manager/IOSFileUpload/ } { status code: 200, headers { "Accept-Ranges" = bytes; Connection = close; "Content-Length" = 345; "Content-Type" = "text/html"; Date = "Tue, 25 Aug 2015 10:52:01 GMT"; "Last-Modified" = "Mon, 24 Aug 2015 03:54:55 GMT"; Server = Apache; } }) JSON nil ERROR Optional(Error Domain=NSCocoaErrorDomain Code=3840 "The operation couldn’t be completed. (Cocoa error 3840.)" (Invalid value around character 0.) UserInfo=0x7f8c68c1c130 {NSDebugDescription=Invalid value around character 0.})
my PHP content:
<? php echo $_FILES['image']['name']. '<br/>'; //ini_set('upload_max_filesize', '10M'); //ini_set('post_max_size', '10M'); //ini_set('max_input_time', 300); //ini_set('max_execution_time', 300); $target_path = "uploads/"; $target_path = $target_path.basename($_FILES['image']['name']); try { //throw exception if can't move the file if (!move_uploaded_file($_FILES['image']['tmp_name'], $target_path)) { throw new Exception('Could not move file'); } echo "The file ".basename($_FILES['image']['name']). " has been uploaded"; } catch (Exception $e) { die('File did not upload: '.$e - > getMessage()); } ?>
My code followed this suggestion: Uploading file with parameters using Alamofire .Please help me, thanks
-
imike over 7 yearsIt doesn't work: 'NSInvalidArgumentException', reason: 'Invalid type in JSON write (UIImage)'
-
Sirop4ik over 7 yearsRob could you please help me with my issue it is also associated with alomofire upload request stackoverflow.com/questions/41977486/…
-
Rob almost 7 yearsJust use the
.uploadProgress
and/or.downloadProgress
as shown in the "Upload Progress" section of README's Uploading Data to a Server.