Crash while uploading image using Alamofire - ios

I'm uploading an image using Alamofire like so..
EDIT: This is the edited code...
for img in images {
let url = "http:my url"
let headers = [
"Accept": "application/json",
"Authorization": self.accessToken
]
if let imageData = (UIImageJPEGRepresentation(img, 0.6)) {
let parameters: [String: String] =
[
"seller_id": "\(self.mySellerId)",
"offline_id": self.prodID,
"is_default": "1",
"sequence": "\(sequenceCount)"
]
Alamofire.upload(multipartFormData: {(multipartFormData) in
let filePath = NSURL(fileURLWithPath: url)
print(imageData)
multipartFormData.append (imageData, withName: "image", fileName: "\(Date().timeIntervalSince1970).jpg", mimeType: "image / jpg")
for (key, value ) in parameters {
print(key,value)
multipartFormData.append(value.data(using: .utf8)!, withName: key)
}
}, to: url, method: .post, headers: headers)
{ (result) in
switch result {
case .success(let upload, _,_ ):
upload.uploadProgress(closure: { (progress) in
UILabel().text = "\((progress.fractionCompleted * 100)) %"
print (progress.fractionCompleted * 100)
})
upload.responseJSON { response in
if let JSON = response.result.value {
print(JSON)
}else{
print("Error")
}
}
case .failure(let encodingError):
print(encodingError)
break
}
}
}
}
In the part for (key, value) in parameters... the for loop goes through all values. But when it reaches the image data part, it crashes saying Could not cast value of type 'Foundation.Data' (0x10787b9f0) to 'Swift.String'
What should be given instead so that the error can be fixed..?

You are casting all values from parameters dictionary as String's, first entry in dictionary is "product_image" and it has imageData as value and that is of type Data.
I would do this, no more force casting.
for (key, value) in parameters {
if let v = value as? String, let valueAsData = v.data(using: .utf8) {
multipartFormData.append(valueAsData, withName: key )
}
}
You could also check if value is already Data type and just add it as well like:
for (key, value) in parameters {
var dataToAppend: Data?
if let data = value as? Data {
dataToAppend = data
} else if let v = value as? String, let valueAsData = v.data(using: .utf8) {
dataToAppend = valueAsData
}
if let d = dataToAppend {
multipartFormData.append(d, withName: key )
}
}

Related

Uploading image to server with parameter error swift

I am trying to upload image to server with folder name, filename and extension as parameter. I have done some code, but it gives me a Nil response. can someone help me to solve that?
Sometimes this uploads image and sometimes don't. And when it failed to upload image gives a Nil response.and sends some garbage value to server.
Here is my image upload method:
func UPLOD(){
let image = myImageView.image!
let serviceName = "http://192.168.80.21:8800/api/v1/upload/uploadfile"
var parameters = [String: AnyObject]()
parameters["Folder"] = "uploadfile" as AnyObject?
parameters["Filename"] = "demo\(self.currentTimeStamp)" as AnyObject?
parameters["Ext"] = "jpg" as AnyObject?
parameters["FileToUpload"] = image.jpegData(compressionQuality: 0.5) as AnyObject?
guard let token = UserDefaults.standard.string(forKey: "accesstoken") else {
return
}
print("Create button ACCESS KEY::::- \(token)")
let headers: HTTPHeaders = [
"x-access-token": token
]
Alamofire.upload(multipartFormData: { (multipartFormData:MultipartFormData) in
for (key, value) in parameters {
if key == "FileToUpload" {
multipartFormData.append(
value as! Data,
withName: key,
fileName: "demo\(self.currentTimeStamp)",
mimeType: "image/jpg"
//_img.jpg
)
} else {
//Data other than image
multipartFormData.append((value as! String).data(using: .utf8)!, withName: key)
}}},
to: serviceName, method: .post, headers: headers) { (encodingResult:SessionManager.MultipartFormDataEncodingResult) in
switch encodingResult {
case .success(let upload, _, _):
upload.responseJSON { response in
//print response.result
print(response.result.value as Any)
}
upload.responseJSON { [self] response in
if let Response = response.result.value as? [String : Any],
let myData = Response["data"] as? [String : Any],
let imgPath = myData["ImagePath"] {
imageUrl = imgPath as! String
print(imageUrl)
print("ImagePath --> ", imgPath)
responseURL = imageUrl
let defaults = UserDefaults.standard
defaults.setValue(imageUrl, forKey: "imageURL")
let key = defaults.object(forKey: "imageURL")
print(key as Any)
self.alamofireRequest(requestURL: "http://192.168.80.21:3204/api/product/create")
}
if let data = response.result.value {
let _ = JSON(data)
}
}
break
case .failure(let encodingError):
print(encodingError)
break
}
}
}
Swift 5.0
pod 'Alamofire', '~> 5.4'
func postImageData(url:String, param:[String:Any], img:Data) {
print("POST URL : ", url)
let header: HTTPHeaders = [
"Content-type": "multipart/form-data"
]
AF.upload(multipartFormData: { (MultipartFormData) in
MultipartFormData.append(img, withName: "image", fileName: "image", mimeType: "image/jpeg")
for (key,value) in param {
MultipartFormData.append((value as! String).data(using: .utf8)!, withName: key)
}
}, to: url, method: .post, headers: header).uploadProgress { (progress) in
print(progress.fractionCompleted)
} .responseJSON { response in
switch response.result {
case .success:
if let JSON = response.value as? [String: Any] {
let flag = JSON["flag"] as! Bool
let code = JSON["code"] as! Int
} else {
}
break
case .failure(let error):
if let data = response.data {
print("Response Error Line No. 265:- \(NSString(data: data, encoding: String.Encoding.utf8.rawValue)!)")
}
break
}
}
}

how to upload image,pdf,audio,video and any file system from iphone local memory to server(API)

I have to upload any kind of file system from local phone memory to API given.Is there a simple way to that please help.
You can use Alamofire library.
https://github.com/Alamofire/Alamofire
Alamofire.upload(multipartFormData: { (multipartFormData) in
if let parameters = parameters {
for (key, value) in parameters {
if let value = value as? String {
multipartFormData.append(value.data(using: .utf8)!, withName: key)
}else if let _image = value as? UIImage, let image = _image.resized(toWidth: 500) {
if let jpegData = image.jpegData(compressionQuality: 0.5) {
multipartFormData.append(jpegData, withName: key, fileName: "post.jpeg", mimeType: "image/jpeg")
}else if let pngData = image.pngData() {
multipartFormData.append(pngData, withName: key, fileName: "post.png", mimeType: "image/jpeg")
}
}else {
multipartFormData.append(Data(from: value), withName: key)
}
}
}
}, usingThreshold: UInt64.init(), to: urlString, method: method, headers: headers, encodingCompletion: { (result) in
switch result {
case .success(let upload, _, _):
upload.responseJSON { response in
if let responseData = response.result.value as? NSDictionary {
completion(responseData, response.data, response.result)
}else if let responseData = response.result.value as? [String: Any] {
completion(responseData as NSDictionary, response.data, response.result)
}else {
completion([:], nil, response.result)
}
}
break
case .failure(let encodingError):
completion([:], nil, .failure(encodingError))
break
}
})

how to append String Array to form data

I want to send file with other parameters.I was able to send that using alamofire upload.but the question is in my parameters i have String arrays.I dont know how to append them in to form data.
let parameters = ["comments":comments!,
"title":title!,
"publish_date":publish_date,
"expiry_date":expiry_date,
"visibility[staff]":"N",
"visibility[students][Forms]":["1","2"]
]
]
as [String : Any]
let headers = [
"Content-type": "multipart/form-data"
]
let URL_head = try! URLRequest(url: STAFF_SERVICE_URL + "staff/2/news?api_key=\(api_key)", method: .post, headers: headers)
Alamofire.upload(multipartFormData: { (multipartFormData) in
if let url = fileUrl{
multipartFormData.append(url, withName: "file")
}
for (key, value) in parameters {
multipartFormData.append("\(value)".data(using: String.Encoding.utf8)!, withName: key as String)
}
print(multipartFormData)
}, with:URL_head)
{ (result) in
switch result {
case .success(let upload, _, _):
upload.responseJSON { response in
NSLog("Upload response \(response)")
if let jsonValue = response.result.value {
_ = JSON(jsonValue)
completion(true ,"Suucess")
}else{
completion(false ,"Error")
}
}
case .failure(let encodingError):
print("fail \(encodingError)")
NSLog("Error \(result)")
completion(false ,"No Internet")
}
}
}
i tried to encode array seperately like this.but not worked.
let data = try! JSONSerialization.data(withJSONObject: array,
options:.prettyPrinted)
let jsonString = String(data: data, encoding: .utf8)!
You can directly pass data object you don't need to convert back to string
for example
for (key, value) in parameters {
if checkIfItIsArray {
// Make sure you handle error here
let data = try! JSONSerialization.data(withJSONObject: array, options:nil)
multipartFormData.append(data, withName: key as String)
} else {
multipartFormData.append("\(value)".data(using: String.Encoding.utf8)!, withName: key as String)
}
}

How to send array in params using Alamofire multipart

I am using Alamofire for uploading image and file to the server. But I am facing issue to send an array in parameters with the image. But when I send an array in params it converts the array in JSON string. But I want to send an array in params, not JSON string. I have searched a lot and did not find any solution. So please tell me what's wrong in my code. I am using below code:
let params = ["id":"112","arrayParam":["1232","12344","14325"]]
let url = www.khxjjhdfsj.com/hsdgs
let headers: HTTPHeaders = [
/* "Authorization": "your_access_token", in case you need authorization header */
"Content-type": "multipart/form-data"
]
Alamofire.upload(multipartFormData: { (multipartFormData) in
for (key, value) in params
{
multipartFormData.append("\(value)".data(using: String.Encoding.utf8)!, withName: key as String)
}
if let data = imageData
{
multipartFormData.append(data, withName: "file", fileName: fileName, mimeType: "image/png")
}
if let data = pdfData
{
multipartFormData.append(data, withName: "file", fileName: fileName, mimeType:"application/pdf")
}
}, usingThreshold: UInt64.init(), to: url, method: .post, headers: headers) { (result) in
switch result{
case .success(let upload, _, _):
upload.responseJSON { response in
print("Succesfully uploaded")
if let err = response.error
{
onError?(err)
return
}
}
case .failure(let error):
print("Error in upload: \(error.localizedDescription)")
onError?(error)
}
}
You need to pass image parameter along with your other request parameters. Pass your array parameters like this in below code:
Alamofire.upload(
multipartFormData: { multipartFormData in
// Pass your image parameter in imgObj
if let imageData = UIImageJPEGRepresentation(imgObj, 1) {
multipartFormData.append(UIImagePNGRepresentation(imgObj)!, withName: "profile_image", fileName: "THDC", mimeType: "image/png")
}
// Send other request parameters
for (key, value) in yourArray {
multipartFormData.append((value as! String).data(using: .utf8)!, withName: key)
}
},to: YourURL,headers:[:],
encodingCompletion: { encodingResult in
switch encodingResult {
case .success(let upload, _, _):
upload.responseJSON { response in
SVProgressHUD.dismiss()
debugPrint("SUCCESS RESPONSE: \(response)")
if let dicObj = response.result.value as? NSDictionary {
print(dicObj)
}
}
case .failure(let encodingError):
SVProgressHUD.dismiss()
print("ERROR RESPONSE: \(encodingError)")
}
}
)
This is the static way to upload arrays to Alamofire.
hope this may useful to you.
Alamofire.upload(multipartFormData: { (multipartFormData) in
let imageData = UIImageJPEGRepresentation(imageUpload!, 0.5)
multipartFormData.append(imageData!, withName: "profile_file", fileName: "file.png", mimeType: "image/jpg")
for (key, value) in parameters {
if (value as AnyObject).isKind(of: NSMutableArray.self)
{
let arrayObj = value as! NSMutableArray
//let data2 = NSData(bytes: &arrayObj, length: arrayObj.count)
let count : Int = arrayObj.count
for i in 0 ..< count
{
let value = arrayObj[i] as! Int
let valueObj = String(value)
let keyObj = key + "[" + String(i) + "]"
multipartFormData.append(valueObj.data(using: String.Encoding.utf8)!, withName: keyObj)
}
}
else{
var valueStr = String()
if let param = value as? String{
valueStr = param
}else{
let valueInt = value as! Int
valueStr = String(valueInt)
}
multipartFormData.append((valueStr).data(using: String.Encoding.utf8)!, withName: key)
}
}
}, to: urlString, encodingCompletion: { (encodingResult) in
print("=====encodingResult=========",encodingResult)
switch encodingResult {
case .success(let upload, _, _):
upload.responseJSON(completionHandler: { (response) -> Void in
switch response.result {
case .success(let JSON):
print("JSON: \(JSON)")
onCompletion(JSON as? NSDictionary, nil)
case .failure(let error):
print(error)
}
})
case .failure(let encodingError):
print(encodingError);
}
})
You need to append array with multipart data on the same key required, like in your code you need to change only given line of code:
for (key, value) in params
{
// check the key on which key array is coming
if key == "arrayParam" {
let arrData = try! JSONSerialization.data(withJSONObject: value, options: .prettyPrinted)
multipartFormData.append(arrData, withName: key as String)
}
else {
multipartFormData.append("\(value)".data(using: String.Encoding.utf8)!, withName: key as String)
}
}
Rest will be the same.

How to append array in multipart form data with Alamofire?

I am uploading image with multipart form data using Alamofire but getting some problem while i am passing an array as parameter.
As per request i need to pass all data into letter.
Here is how i am doing.
let data = try! JSONSerialization.data(withJSONObject: arrSelectedRecipientsID, options: .prettyPrinted)
let jsonString = String(data: data, encoding: .utf8)!
let paramArr : [String : Any] = [
"message" : txtvwMessage.text!,
"status": "draft",
"recipient_ids": jsonString
]
let parameter : [String : Any] = ["letter" : paramArr]
let accesstoken = Utilities.retriveValueFromDefault(forKey: UDKey.kUserAuthentication_Token) as String
let client = Utilities.retriveValueFromDefault(forKey: UDKey.kUserClient) as String
let uid = Utilities.retriveValueFromDefault(forKey: UDKey.kUserUID) as String
let headersInfo : HTTPHeaders = [ "Content-Type" : "multipart/form-data",
"Accept" : "application/json",
"access-token" : accesstoken,
"client" : client,
"uid" : uid
]
fileUploadWithParameter(Constant.ServerAPI.kPostLetters, images: letterImage, header: headersInfo, parameters: parameter, success: { (response) in
print(response)
}) { (progress) in
}
Here is Alamofire request method.
func fileUploadWithParameter(_ url: String,images:NSMutableArray,header : [String : String], parameters: [String:Any], success:#escaping (NSDictionary)->(),progressHandler:#escaping(_ progress: Double)->Void) {
Alamofire.upload(multipartFormData: { multipartFormData in
for i in 0..<images.count {
let rotatedImage = images[i] as! UIImage
if let imgData = UIImageJPEGRepresentation(rotatedImage, 0.8) {
multipartFormData.append(imgData, withName: "letter[photos]",fileName: "0\(i).jpg", mimeType: "image/jpg")
}
}
for (key, value) in parameters {
//multipartFormData.append((value as AnyObject).data(using: String.Encoding.utf8.rawValue)!, withName: key )
let paramsData:Data = NSKeyedArchiver.archivedData(withRootObject: value)
multipartFormData.append(paramsData, withName: key)
}
}, to: url,
method:.post,
headers:header) { (result) in
print("\n\n\nRequest URL :- \(url)\nParameters :- \(parameters)")
switch result {
case .success(let upload, _, _):
upload.responseJSON { response in
if response.error != nil {
print("Error :- \((response.error?.localizedDescription)!)\n\n\n")
}
if let jsonDict = response.result.value as? NSDictionary {
print("Response :- \(jsonDict)\n\n\n")
} else {
print("Error :- \(Constant.ErrorMessage.kCommanError)\n\n\n")
}
}
case .failure(let encodingError):
print("Error :- \(encodingError.localizedDescription)\n\n\n")
}
}
}
Postman works well so can someone please help me where i am doing wrong.
API expected The proper json should be
{
"letter":
{
"message": "Type your message here...!!!",
"recipient_ids": [183, 184],
"status": "draft"
}
}
API is in ruby on rails and it says i am sending string. Please help me to find out what is issue.
Jus need to change only given line of code:
for (key, value) in parameters {
if key == "letter" {
let arrData = try! JSONSerialization.data(withJSONObject: value, options: .prettyPrinted)
multipartFormData.append(arrData, withName: key as String)
}
else {
multipartFormData.append("\(value)".data(using: String.Encoding.utf8)!, withName: key as String)
}
}
Rest will be the same.
your method in updated form:
func fileUploadWithParameter(_ url: String,images:NSMutableArray,header : [String : String], parameters: [String:Any], success:#escaping (NSDictionary)->(),progressHandler:#escaping(_ progress: Double)->Void) {
Alamofire.upload(multipartFormData: { multipartFormData in
for i in 0..<images.count {
let rotatedImage = images[i] as! UIImage
if let imgData = UIImageJPEGRepresentation(rotatedImage, 0.8) {
multipartFormData.append(imgData, withName: "letter[photos]",fileName: "0\(i).jpg", mimeType: "image/jpg")
}
}
for (key, value) in parameters {
//multipartFormData.append((value as AnyObject).data(using: String.Encoding.utf8.rawValue)!, withName: key )
let paramsData:Data = NSKeyedArchiver.archivedData(withRootObject: value)
multipartFormData.append(paramsData, withName: key)
}
for (key, value) in parameters {
if key == "letter" {
let arrData = try! JSONSerialization.data(withJSONObject: value, options: .prettyPrinted)
multipartFormData.append(arrData, withName: key as String)
}
else {
multipartFormData.append("\(value)".data(using: String.Encoding.utf8)!, withName: key as String)
}
}
}, to: url,
method:.post,
headers:header) { (result) in
print("\n\n\nRequest URL :- \(url)\nParameters :- \(parameters)")
switch result {
case .success(let upload, _, _):
upload.responseJSON { response in
if response.error != nil {
print("Error :- \((response.error?.localizedDescription)!)\n\n\n")
}
if let jsonDict = response.result.value as? NSDictionary {
print("Response :- \(jsonDict)\n\n\n")
} else {
//print("Error :- \(Constant.ErrorMessage.kCommanError)\n\n\n")
print("Errfdc")
}
}
case .failure(let encodingError):
print("Error :- \(encodingError.localizedDescription)\n\n\n")
}
}
}
Finally get it done with separate append in request. Here is how you can pass an array in multipart form data request.
Alamofire.upload(multipartFormData: { multipartFormData in
for i in 0..<self.letterImage.count {
let rotatedImage = self.letterImage[i] as! UIImage
if let imgData = UIImageJPEGRepresentation(rotatedImage, 0.8) {
multipartFormData.append(imgData, withName: "letter[photos][]",fileName: "0\(i).jpg", mimeType: "image/jpg")
}
}
multipartFormData.append("\(message)".data(using: String.Encoding.utf8)!, withName: "letter[message]")
multipartFormData.append("draft".data(using: String.Encoding.utf8)!, withName: "letter[status]")
for (_,value) in self.arrSelectedRecipientsID.enumerated() {
multipartFormData.append("\(value)".data(using: String.Encoding.utf8)!, withName: "letter[recipient_ids][]")
}
}
you can append array of like below
for image attachments
for Attachment in Attachments
{
if let pic = Attachment{
let randome = arc4random()
let data = UIImageJPEGRepresentation(pic, 0.8)
MultipartFormData.append(data!, withName: "letter[photos][]", fileName: "randome\(randome).jpg", mimeType: "image/jpg")
}
}
for parameters
for (key,value) in params
{
MultipartFormData.append("\(value)".data(using: String.Encoding.utf8)!, withName: "\(key)")
}

Resources