I'm trying to call an API in which I'm trying to send some parameters and array of images, but when I hit the API I get an error, Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSCFNumber dataUsingEncoding:]: unrecognized selector sent to instance 0xfb47bab3e1e91166'. I have checked through breakpoint it crashes on parameters, I'm confused why it is giving this error, my code for the API is this,
func addAPI()
{
let headers: HTTPHeaders = [
/* "Authorization": "your_access_token", in case you need authorization header */
"Content-type": "multipart/form-data"
]
let parameters :[String: Any] = ["name":productNameTxt.text!,
"price":priceTxt.text!,
"size": sizeTxt.text!,
"weight":weightTxt.text!,
"quality":qualityTxt.text!,
"brand":brandTxt.text!,
"shippingCost":shippingCostTxt.text!,
"details":detailTxt.text!,
"material_id":materialId,
"material_type_id": subMaterialId,
"maxQuantity":4]
Alamofire.upload(multipartFormData: { multipartFormData in
for (key, value) in parameters {
if let data = ((value) as AnyObject).data(using: String.Encoding.utf8.rawValue) {
multipartFormData.append(data, withName: key)
}
}
for (index, image) in self.imageArray.enumerated() {
multipartFormData.append(image.pngData()!, withName: "file", fileName: "image\(index).png", mimeType: "image/png")
}
// for i in 0..
},
to: addProductUrl,method:HTTPMethod.post,
headers:headers, encodingCompletion: { encodingResult in
switch encodingResult {
case .success(let upload, _, _):
upload
.validate()
.responseJSON { response in
switch response.result {
case .success(let value):
// compBlock(value as AnyObject,true)
print("responseObject: \(value)")
case .failure(let responseError):
print("responseError: \(responseError)")
}
}
case .failure(let encodingError):
print("encodingError: \(encodingError)")
let errorDesc = (encodingError as NSError).localizedDescription
//failure(errorDesc as NSString,false)
}
})
}
What is this error for and how I can remove it?
From here
if let data = ((value) as AnyObject).data(using: String.Encoding.utf8.rawValue) {
then any passed value have to be converted to Data and since you specify an integer ( NSNumber when wrapped inside json) hence the crash so change 4 to "4" and
"material_id":"\(materialId)",
It would be better if you follow like this:
//[String:String] instead of [String : Any]
let parameters :[String: String] = ["name":productNameTxt.text!,
"price":priceTxt.text!,
"size": sizeTxt.text!,
"weight":weightTxt.text!,
"quality":qualityTxt.text!,
"brand":brandTxt.text!,
"shippingCost":shippingCostTxt.text!,
"details":detailTxt.text!,
"material_id":"\(materialId)",
"material_type_id": subMaterialId,
"maxQuantity":4]
multipartFormData.append((value.data(using: .utf8))!, withName: key)
Related
In the postman in the body section in the form-data part when I pass a mobile number as a key and mobile number as Int value I get a response. But when I did it in the code I will not get the response as expected.
my code is
func fetchRegisterData(){
let url = registerApi
var mobileNumber = mobilenumberTextfield.text
let parameters = ["mobile" : mobileNumber] as [String : Any]
AF.request(url,method: .post, parameters: parameters, encoding:JSONEncoding.default).responseJSON
{ response in switch response.result {
case .success(let JSON):
print("response is :\(response)")
case .failure(_):
print("fail")
}
}
}
If you're trying to pass parameters as multipart/form-data you have to use the upload method in Alamofire:
func fetchRegisterData() {
let parameters = ["mobile": mobilenumberTextfield.text!]
AF.upload(multipartFormData: { (multiFormData) in
for (key, value) in parameters {
multiFormData.append(Data(value.utf8), withName: key)
}
}, to: registerApi).responseJSON { response in
switch response.result {
case .success(let JSON):
print("response is :\(response)")
case .failure(_):
print("fail")
}
}
}
For normal Alamofire request -
While passing values as a parameter in Alamofire Request. You need to know about the data type of the request type values which is valid for API.
At API end, these values are getting parsed based on some data types. There must be some validations on the data type at the API side.
for mobileNumber, it can be either Int or String
1 - let parameters = ["mobile" : mobileNumber] as [String : Int]
2 - let parameters = ["mobile" : mobileNumber] as [String : String]
For multipart form data request use have to use something like below. However, if you are not uploading anything you should not use it. Ask API team to make changes in the API and normal parameters request
Alamofire.upload(multipartFormData: { (multipartFormData) in
//Try this
multipartFormData.append(mobileNumber, withName: "mobile")
//or this
multipartFormData.append("\(String(describing: mobileNumber))".data(using: .utf8)!, withName: "mobile")
}, usingThreshold: 10 * 1024 * 1024, to: apiUrl, method: .post, headers: [:], encodingCompletion: { (encodingResult) in
switch encodingResult {
case .success(let upload, _, _):
case .failure( _):
}
})
i am using this code to send an image and text to an api:
func uploadImageAndData(_ url:String,parameters1:Parameters,headers1:HTTPHeaders,images:[UIImage]){
Alamofire.upload(multipartFormData: { multipartFormData in
// import image to request
var i=0
for imageData in images {
// multipartFormData.append(self.resizeImage(image: uploadedProfileImage, targetSize: CGSize(width: 200, height: 200)
multipartFormData.append(imageData.pngData()!, withName: "profilePic", fileName: "profileimage"+".jpeg", mimeType: "image/jpeg")
i += 1
}
for (key, value) in parameters1 {
multipartFormData.append((value as AnyObject).data(using: String.Encoding.utf8.rawValue)!, withName: key)
}
} ,to: url,method:.post,
headers:[:],
encodingCompletion: { encodingResult in
switch encodingResult {
case .success(let upload, _, _):
upload.uploadProgress(closure: { (Progress) in
print("showuing upload progress")
print("Upload Progress: \(Progress.fractionCompleted)")
//SwiftSpinner.show(progress: Progress.fractionCompleted*100, title: "تحميل")
})
upload.responseJSON { response in
print(response.response?.statusCode as Any)
if let data = response.result.value, let utf8Text = String(data: data as! Data, encoding: .utf8) {
print("New Func Data: \(utf8Text)")
}
switch response.response?.statusCode {
case 201 :
print("Success")
break
case 413 :
print("Post too large")
break
case 200 :
print("200")
break
case 400 :
print("400")
break
case 401 :
print("401")
break
case 302 :
print("302")
break
case 500 :
print("500")
break
default: break
}
}
return
case .failure(let encodingError): break
}
})
}
and i got these datas :
let address: Parameters = [
"location" : addressField.text!,
"locationLat" :pickedLocationLat,
"locationLong" :pickedLocationLong
]
let body: Parameters = [
"name": "Sample Name",
"email": "test#test.com",
"password": "test123",
"address": address
]
and i am accessing the function using this code
var head = [String:Any]()
head["Accept"]="application/json"
uploadImageAndData(BASE_URL", parameters1: body, headers1: head as! HTTPHeaders, images: [uploadedProfileImage])
this code is throwing an error like
Terminating app due to uncaught exception 'NSInvalidArgumentException'
reason: '-[_TtGCs26_SwiftDeferredNSDictionarySSP__$ dataUsingEncoding:]: unrecognized selector sent to instance 0x6000015bed00'
terminating with uncaught exception of type NSException
i dont know what is causing this problem the api requires a json body with a content-type of application/json
i tired removing all the content of the body parameter except for the name to try and send only the name and when i do that the image uploads successfully but it still gives me this error,so please help me figure out this problem.
You need to make values a string not double
let address: Parameters = [
"location" : addressField.text!,
"locationLat" :"\(pickedLocationLat)",
"locationLong" :"\(pickedLocationLong)"
]
I am able to upload a photo via Postman but in my iOS application it fails, and it is so weird that I still get a .success from encodingCompletion.
Here is part of my code
UpdateUserInfo
//
// Update user info
//
func updateUserInfo(){
var imageData: Data!
var url = ""
if let userId = KeychainWrapper.standard.string(forKey: USER_ID_KEY){
url = URL_USER_UPLOAD_PIC + userId
}
if pickedImage != nil{
imageData = UIImagePNGRepresentation(pickedImage)
//imageData = UIImageJPEGRepresentation(pickedImage!, 1.0)
}
let token = KeychainWrapper.standard.string(forKey: USER_LOGIN_TOKEN_KEY)!
let headers: HTTPHeaders = [
"Authorization": "Bearer \(token)"
]
if imageData != nil{
Alamofire.upload(multipartFormData: { (multipartFormData) in
multipartFormData.append(imageData!, withName: "fileset", fileName: "file.png", mimeType: "image/png")
}, to: url,
method: .post,
headers: headers,
encodingCompletion: { encodingResult in
switch encodingResult {
case .success(let upload, _, _):
print("Donkey Success \(String(describing: upload.response?.statusCode))")
upload.responseString(completionHandler: { (response) in
debugPrint(response)
})
case .failure(let encodingError):
print(encodingError)
print("Donkey Fail")
}
})
}
}
and in my postman I have
Postman
My first question is why I am getting a .success if it fails to upload?
and my second question is, do I need to put the key "pic" (seen in Postman) somewhere in my request? if so where?
Thanks for any help in advance
In Post man Image Key is pic but in your code its "fileset"
change to
multipartFormData.append(imageData!, withName: "pic", fileName: "file.png", mimeType: "image/png")
And success is Result of encoding not uploading processs
EncodingResult is MultipartFormDataEncodingResult that Defines
whether the MultipartFormData encoding was successful and contains
result of the encoding as associated values. - Success: Represents a successful MultipartFormData encoding and contains the
new UploadRequest along with
streaming information. - Failure: Used to represent a failure in the MultipartFormData encoding and also
contains the encoding
I'm trying convert code for Swift 3 and Alamofire 4, and I'm currently struggling with the following error:
Cannot call value of non-function type '((UInt) -> Data?)!'
at this line:
multipartFormData.append(data: value!.data(using: String.Encoding.utf8.rawValue)!, name: key)
Please give your advice for this case. My current code is below.
Alamofire.upload(
multipartFormData: { multipartFormData in
multipartFormData.append(imageData!, withName: "image", fileName: nowString + "To" + receiverString! + ".jpg", mimeType: "image/jpg")
for (key, value) in parameters {
multipartFormData.append(data: value!.data(using: String.Encoding.utf8.rawValue)!, name: key)
}
},to:"uploadimgURL"
encodingCompletion: { encodingResult in
switch encodingResult {
case .success(let upload, _, _)
upload.responseString(completionHandler: { (response) in
debugPrint(response)
})
case .failure(let encodingError):
print(encodingError)
}
}
)
I do see one issue with the line in question. Try not using the raw value of the enum like so:
let stringValue = value as! String
multipartFormData.append(data: stringValue.data(using: .utf8)!, name: key)
Updated Alamofire 4.0.0 does not mention how to put Httpmethod & Httpheaders in upload with multipartFormData. That's why I google and found solution in that stackoverflow question. But the problem is I did same as that answer then got following error message and building is failed. Please help me how to solve it.
Type of expression is ambiguous without more context
Here is my coding:
let URL = try! URLRequest(url: Config.imageUploadURL, method: .post, headers: headers)
Alamofire.upload(
multipartFormData: { multipartFormData in
multipartFormData.append(self.imageData, withName: "image", fileName: "file.png", mimeType: "image/png")
},
to: URL,
encodingCompletion: { encodingResult in
switch encodingResult {
case .success(let upload, _, _):
upload.responseJSON { response in
if((response.result.value) != nil) {
} else {
}
}
case .failure( _):
}
}
)
Alamofire.upload(multipartFormData:to:encodingCompletion:) takes a URLConvertible for the to: argument. Instead, you should use Alamofire.upload(multipartFormData:with:encodingCompletion:) which takes a URLRequestConvertible for its with: argument.
I think your argument name of URL that is the same as the type URL() helps in creating strange compiler errors.
The following compiles for me:
let url = try! URLRequest(url: URL(string:"www.google.com")!, method: .post, headers: nil)
Alamofire.upload(
multipartFormData: { multipartFormData in
multipartFormData.append(Data(), withName: "image", fileName: "file.png", mimeType: "image/png")
},
with: url,
encodingCompletion: { encodingResult in
switch encodingResult {
case .success(let upload, _, _):
upload.responseJSON { response in
if((response.result.value) != nil) {
} else {
}
}
case .failure( _):
break
}
}
)
For me the build error was caused by a multipartFormData.appendBodyData(). After replacing it with multipartFormData.append() the problem was solved.
I got the same error, after spending lots of time, i found that issue was:
I was passing MutableURLRequest instead of passing URLRequest object. Thats why i were getting this error. After type casting it to URLRequest, it start working.