I need to upload several images to an API at a time. I am using Alamofire to upload images and the API only allows one image to be uploaded per request.
I have an array of images to be uploaded and I am going through the array and making a request each time. Each image appears to upload correctly but then when I check the database only the last image has been uploaded. Each call prints a response with status code 200 and prints "SUCCESSFUL" when it is complete, but only the last in the array actually uploads.
for (index, image) in self.imageArray.enumerated() {
self.uploadImages(photoIndex: index, photo: image.image, fileName: image.imageName, completion: { (true) in
print("SUCCESSFUL")
})
}
I have also tried using a DispatchQueue, but that didn't work either:
let serialQueue = DispatchQueue(label: "serialQueue")
And inside the for loop
serialQueue.async {
//self.uploadImages...
}
I've tried a few more things, with no success. How would I be able to fix this?
Also, here is my uploadImages function
func uploadImages(photoIndex: Int, photo: UIImage, fileName: String, completion: #escaping (_ Success : Bool?) -> ())
{
var success: Bool? = nil
let url : String? = //url
// define parameters
let parameters = [
"photoIndex": "\(photoIndex)"]
Alamofire.upload(multipartFormData: { multipartFormData in
if let imageData = UIImageJPEGRepresentation(photo, 1)
{
multipartFormData.append(imageData, withName: "photo", fileName: fileName, mimeType: "image/png")
}
for (key, value) in parameters {
multipartFormData.append((value.data(using: .utf8))!, withName: key)
}}, to: url!, method: .post,
encodingCompletion: { encodingResult in
switch encodingResult {
case .success(let upload, _, _):
upload.response { [weak self] response in
guard let strongSelf = self else {
return
}
success = true
debugPrint(response)
completion(success)
}
case .failure(let encodingError):
print("error:\(encodingError)")
}
})
}
Use multipart form data to upload the any media file below is the code snippet to upload multiple video
for (key , value) in arrMediaUpload {
if let image = value as? UIImage {
if let imageData = UIImageJPEGRepresentation(image,0.9) {
print("key => \(key)")
multipartFormData.append(imageData as Data, withName: key, fileName: "\(NSDate().timeIntervalSince1970).jpg", mimeType: "image/*")
}
}
}
I am not that good in Swift so take this answer with a grain of salt but I do not see were you are adding any new keys to your dictionary. So since there is only one key there would be only one value. Therefore the for loop would only be done one time.
Related
I am trying to upload an image to server , but its showing its not current format , I have seen so many solutions in stack , but haven't work on my code .
here is the screenshot of my postman : postman response for auth:
Screenshot of Authorization page
code I have tried with Alamofire : `
func upload(image: Data, to url: Alamofire.URLRequestConvertible, params: [String: Any]) {
AF.upload(multipartFormData: { multiPart in
for (key, value) in params {
if let temp = value as? String {
multiPart.append(temp.data(using: .utf8)!, withName: key)
}
if let temp = value as? Int {
multiPart.append("\(temp)".data(using: .utf8)!, withName: key)
}
if let temp = value as? NSArray {
temp.forEach({ element in
let keyObj = key + "[]"
if let string = element as? String {
multiPart.append(string.data(using: .utf8)!, withName: keyObj)
} else
if let num = element as? Int {
let value = "\(num)"
multiPart.append(value.data(using: .utf8)!, withName: keyObj)
}
})
}
}
multiPart.append(image, withName: "file", fileName: "file.png", mimeType: "image/png")
}, with: url)
.uploadProgress(queue: .main, closure: { progress in
//Current upload progress of file
print("Upload Progress: \(progress.fractionCompleted)")
})
.responseJSON(completionHandler: { data in
//Do what ever you want to do with response
})
}
`
now I need help to upload the image using url session or Alamofire .
need help about parameter to url: also.
the url is : "http://germanbutcher.easyservice.xyz/backend/api/v1/users/33/photo"
thanks in advance
During resistration of a user, i am uploading some photoes to the server. The first one is the profile photo. And the rest photoes i want to upload after the resistration process once completed. Means i want to upload the photo after getting the userid and the access token.Means after a successfully image upload, the user will enter to the "matchesViewController" and then only the upload process will start. Also i want to upload these photoes in background thread. Also if the app rinning in background then also the upload process should be continue. All the uploading process is done by Alamofire.
By writting the following code the photos are uploading successfully, but it is taking more time. Which is not a good user experience.
Also please tell me how to continue the upload process when the app running in back ground thread.
Also if the code is not good please help me to modify any changes in code if needed.
My code is: -
private func handleRegistration (_ parameterDict : [String : Any]){
let url = USER_REGISTER_URL
let headers: HTTPHeaders = [
"Content-Type": "application/x-www-form-urlencoded"
]
Alamofire.upload(multipartFormData: { (multipartFormData) in
for (key, value) in parameterDict {
multipartFormData.append("\(value)".data(using: String.Encoding.utf8)!, withName: key as String)
}
let random = randomString(length: 7)
multipartFormData.append(self.selectedProfilePic.image!.jpegData(compressionQuality: 0.4)!, withName: "fileset",fileName: "\(random).jpg", mimeType: "image/jpg")
}, usingThreshold: UInt64.init(), to: url, method: .post, headers: headers) { (result) in
switch result{
case .success(let upload, _, _):
upload.responseJSON { response in
print(response)
var userId: String?
var token: String?
if let result = response.result.value {
let JSON = result as! NSDictionary
guard let accessToken = JSON["access_token"] as? String
else{ return }
guard let uid = JSON["User_Id"] as? String
else{return}
userId = uid
token = "bearer " + accessToken
UserDefaults.standard.set(Int(uid), forKey: "User_Id")
UserDefaults.standard.set(token, forKey: "access_token")
let phone = JSON["Phone_Number"] as? String
let FirstName = JSON["FirstName"] as? String
let email = uid + "#gmail.com"
let tempDictionary : Dictionary = [kFIRSTNAME : FirstName!, kLASTNAME : "", kFULLNAME : FirstName!, kPHONE : phone!, kREGISTERUSEID: userId, kEMAIL: email] as [String : Any]
self.checkDeviceTokenAvailibility(uid: Int(userId!)!)
self.startRegistrationWithFirebase( detailDict: tempDictionary)
let storyBoard = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "MainTabbarView")
storyBoard.modalPresentationStyle = .fullScreen
self.present(storyBoard, animated: true, completion: nil)
if let message = JSON["Message"] as? String{
if message == "Please Upload a image."{
}
}
}
if userId != nil && token != nil{
self.multiImageUpload(userId: Int(userId!)!, token: token!)
}
print("Succesfully uploaded")
if let err = response.error{
// onError?(err)
// print(err.localizedDescription)
return
}
// onCompletion?(nil)
}
case .failure(let error):
print("Error in upload: \(error.localizedDescription)")
// onError?(error)
}
}
}
One way to make the upload time a lot less is to send multiple parts at once using a for loop and using Alamofire to send a specific part. That way, it breaks it up into parts that take a lot less time to send. The con is that on the server side you will have to reconstruct the image.
Also if the code is not good please help me to modify any changes in code if needed.
It seems you have a lot of arbitrary space in your code.
I am trying to upload an image using swift to the server. i tried NSMutableURLRequest with URLSession. i received network connection lost. I thought it will be a better way to simply use Alamofire but got into a problem as xcode doesn't find the function update.
Any idea how to upload image with Alamofire? or find the update func?
the code for alamofire:
func uploadImageWithAlmofire(url: String) {
let params: Parameters = ["name": "abcd", "gender": "Male"]
Alamofire.upload(multipartFormData:
{
(multipartFormData) in
multipartFormData.append(UIImageJPEGRepresentation(self.yourimageView.image!, 0.1)!, withName: "file", fileName: "file.jpeg", mimeType: "image/jpeg")
for (key, value) in params
{
multipartFormData.append((value as AnyObject).data(using: String.Encoding.utf8.rawValue)!, withName: key)
}
}, to:url,headers:nil)
{ (result) in
switch result {
case .success(let upload,_,_ ):
upload.uploadProgress(closure: { (progress) in
//Print progress
})
upload.responseJSON
{ response in
//print response.result
if response.result.value != nil
{
let dict :NSDictionary = response.result.value! as! NSDictionary
let status = dict.value(forKey: "status")as! String
if status=="1"
{
print("DATA UPLOAD SUCCESSFULLY")
}
}
}
case .failure(let encodingError):
break
}
}
}
When you check Uploading Data to a Server example, it uses AF instead of Alamofire:
AF.upload(multipartFormData: { multipartFormData in
multipartFormData.append(Data("one".utf8), withName: "one")
multipartFormData.append(Data("two".utf8), withName: "two")
}, to: "https://httpbin.org/post")
.responseJSON { response in
debugPrint(response)
}
Try with this
AF.upload(multipartFormData: { multipartFormData in
multipartFormData.append(Data(self.businessType.utf8), withName: "business_type")
let theFileName1 = (self.doc1.absoluteString as NSString).lastPathComponent
multipartFormData.append(self.doc1, withName: "key_value", fileName: theFileName1, mimeType: "image/png")
}, to: "https://www.test_document.php") //POST URL
.responseJSON { response in
debugPrint(response)
}
I have working code that uploads my video, title and description to YouTube using Swift and Alamofire.
My description uploads to YouTube as one line and I would like to split the line to break after each variable.
My description variable is like so:
myDescription = (price! as! String) + " " + (package! as! String)
When that get's sent to YouTube, it appears as:
"Pricehere PackageName"
I want the PackageName to show in the YouTube description with a line break like:
"Pricehere
PackageName"
I had done this in Objective C on an old project like this:
NSString *description = [NSString stringWithFormat:#"%#\n%#\n%#\n%#\n%#\n%#", str1, str2, str3, str4, str5, str6];
When that was passed to YouTube it added each variable and then did a line break.
Thanks for any help.
edit adding in the function for the YouTube Upload for reference:
func postVideoToYouTube(token: String, callback: #escaping (Bool) -> Void){
let headers = ["Authorization": "Bearer \(token)"]
let urlYoutube = "https://www.googleapis.com/upload/youtube/v3/videos?part=snippet"
let path = videoURL?.path
let videodata: Data = NSData.dataWithContentsOfMappedFile(path!)! as! Data
upload(
multipartFormData: { multipartFormData in
multipartFormData.append("{'snippet':{'title' : '\(self.myTitle)', 'description': '\(self.myDescription)'}}".data(using: String.Encoding.utf8, allowLossyConversion: false)!, withName: "snippet", mimeType: "application/json")
multipartFormData.append(videodata, withName: "video", fileName: "video.mp4", mimeType: "application/octet-stream")
},
to: urlYoutube,
method:Alamofire.HTTPMethod.post,
headers:headers,
encodingCompletion: { encodingResult in
switch encodingResult {
case .success(let upload, _, _):
upload.responseJSON { response in
print(response)
let result = response.result.value
let JSON = result as! NSDictionary
let videoId = JSON.object(forKey: "id") as! String
print("VideoID: ", videoId)
self.addVideoToPlaylist(videoId: videoId, callback: { (result) in
callback(result)
})
}
break
case .failure(let encodingError):
print(encodingError)
callback(false)
break
}
}
)
}
Be careful with force casting variables like you're doing, I would recommend you to do something like this:
if let price = price as? String, let package = package as? String {
myDescription = "\(price)\n\(package)"
}
This way you're safe unwraping and also using String Interpolation to construct the string, you can read more in the documentation.
How can i upload a file with the alamofire Router? Struggling with it.
I'm also interested how i can upload file and parameters in the same request with Alamofire router.
Thanks!
I upload an image using the following code. For a given file type, you should be able to adjust the multipartEncoding block accordingly.
let json: [String : Any] = ["key", "value"]
let image = UIImage(named: "Something")!
guard let imageData = UIImagePNGRepresentation(image) else {
// We couldn't convert the image into data :(
}
let multipartEncoding: (MultipartFormData) -> Void = { multipartFormData in
multipartFormData.append(imageData, withName: "image", fileName: "image.png", mimeType: "image/png")
}
let request = Router.uploadPicture(parameters: json) // This is just a plain POST
sessionManager.upload(
multipartFormData: multipartEncoding,
with: request,
encodingCompletion: { (encodingResult) in
switch encodingResult {
case .success(let request, _, _):
request.validate().responseJSON(completionHandler: { (dataResponse) in
if let error = dataResponse.result.error {
// Network request failed :(
}
// SUCCESS!
})
case .failure(_):
// Couldn't encode the image :(
}
})
This is assuming your Router looks something like this.
enum Router: URLRequestConvertible {
case uploadPicture(parameters: Parameters)
static var baseUrl = "https://website.com/"
var method: HTTPMethod {
switch self {
case .uploadPicture(_):
return .post
}
}
var path: String {
switch self {
case .uploadPicture(_):
return "api/upload-picture/"
}
}
// MARK: - URLRequestConvertible
func asURLRequest() throws -> URLRequest {
let url = try Router.baseUrl.asURL().appendingPathComponent(path)
var urlRequest = try URLRequest(url: url, method: method)
var encodedUrlRequest: URLRequest?
switch self {
case .uploadPicture(let parameters):
encodedUrlRequest = try? JSONEncoding.default.encode(urlRequest, with: parameters)
}
return encodedUrlRequest ?? urlRequest
}
}