0

I am using Alamofire for sending request to the server. Now I have to send an array of images(Multiple images) to the server with other parameters. Maximum 4 images I have to send. Please someone helps me, how to solve this task. I checked StackOverflow for a solution but all solutions are like sending the single image to the server. But I want to send multiple images using Alamofire because I have array of images.

This is my code

func clockOutFor(userId: NSNumber, projectId: NSNumber, taskId: NSNumber, latitude: CLLocationDegrees, longitude: CLLocationDegrees, deviceClockOutTime: String, actualEndTime: String, clockOutNetworkInfo: String, clockOutBatteryStatus: String, totalDistance: NSNumber, durationTime: String, customeLabel1: String, customeLabel2: String, customeLabel3: String, customeLabel4: String, customeLabel5: String, imageDataArray: NSArray, completionHandler: @escaping CompletionBlock ) -> Void
    {
        let parameter : Parameters = ["gs_userId":userId, "gs_taskId":taskId, "gs_project_id":projectId, "gs_actual_end":actualEndTime, "gs_actual_end_lattitude":latitude, "gs_actual_end_longitude":longitude, "gs_clockout_device_time":deviceClockOutTime, "gs_clockout_network_status":clockOutNetworkInfo, "gs_clockout_battery_status":clockOutBatteryStatus, "gs_distance":totalDistance, "gs_time_taken":durationTime, "gs_custom1_label":customeLabel1, "gs_custom1_labe2":customeLabel2, "gs_custom1_labe3":customeLabel3, "gs_custom1_labe4":customeLabel4, "gs_custom1_labe5":customeLabel5] as [String : AnyObject]
        let url = "clockout-update"
        let fullUrl = baseUrl?.appendingPathComponent(url)
        let headers: HTTPHeaders = [
            "Authorization" : "Bearer \(token!)",
            "Accept": "application/json",
            "Connection": "keep-alive",
            "Content-type": "multipart/form-data"
        ]
        if token != nil {

            Alamofire.upload(multipartFormData: { multipartFormData in
                for i in 0..<imageDataArray.count{
                    let imageData1 = UIImageJPEGRepresentation(imageDataArray[i] as! UIImage, 1.0)!
                    multipartFormData.append(imageData1, withName: "morephoto[\(i)]" , fileName: "photo" + String(i) + ".jpg", mimeType: "image/jpeg")
                }
                for (key, value) in parameter {
                    print("Key and Value = ",key, value)
                    if let data = (value as AnyObject).data(using: String.Encoding.utf8.rawValue) {
                        multipartFormData.append(data, withName: key)
                    }
                }
            },
                             to: fullUrl!,method:HTTPMethod.post,
                             headers:headers, encodingCompletion: { encodingResult in
                                switch encodingResult {
                                case .success(let upload, _, _):
                                    upload
                                        .validate()
                                        .responseJSON { response in
                                            print(response.request as Any)  // original URL request
                                            print(response.response as Any) // URL response
                                            print(response.data as Any)     // server data
                                            print("Result",response.result)   // result of response serialization
                                            print("parameters = \(parameter)")

                                            switch response.result {
                                            case .success(let value):
                                                completionHandler(value as AnyObject, "No error found")
                                                print("responseObject: \(value)")
                                            case .failure(let responseError):
                                                print("responseError: \(responseError)")
                                            }
                                    }
                                case .failure(let encodingError):
                                    print("encodingError: \(encodingError)")
                                    let errorDesc = (encodingError as NSError).localizedDescription
                                    completionHandler(errorDesc as NSString,"Some error found")
                                }
            })
        }
    }

Here I am getting one error in this line

if let data = (value as AnyObject).data(using: String.Encoding.utf8.rawValue) 

I think it is expecting only string parameters but I have both String and NSNumber. So here is my question, How to encode both values string and NSNumber. Plese someone help/advise me.

Ram
  • 3
  • 2
  • 8
  • Can you posts examples of code you've tried? – SirCJ Jul 19 '18 at 11:00
  • This might help you https://stackoverflow.com/questions/49230181/swift-4-select-multiple-images-and-display-them-in-image-views – Saurabh Jul 19 '18 at 11:03
  • Use https://github.com/hyperoslo/ImagePicker for mutiple images and pass this to parameter as a string – Dilip Tiwari Jul 19 '18 at 11:12
  • Yeah @DilipTiwari i will check – Ram Jul 19 '18 at 11:17
  • if any help req let me know i m already using above link and sending multiple parameters with multiple images array – Dilip Tiwari Jul 19 '18 at 11:18
  • yeah sure @DilipTiwari thanks for advising – Ram Jul 19 '18 at 11:22
  • _But I want to send multiple images using Alamofire because I have array of images._ - that depends on your server - does it even support multiple images as parameters? In what format? – mag_zbc Jul 19 '18 at 11:31
  • No , My images are in array, and parameter as [String : Any] – Ram Jul 19 '18 at 11:43
  • Possible duplicate of [Upload multiple images in swift using Alamofire](https://stackoverflow.com/questions/41499768/upload-multiple-images-in-swift-using-alamofire) – Kuldeep Jul 19 '18 at 12:19

3 Answers3

0

Use this Method to upload Array of images on the server. (if your server accepts them).

class func uploadImageCall(arrayOfImageToUpload:[UIImage]){

      Alamofire.upload(multipartFormData: { (multipartFormData : MultipartFormData) in

                let count = arrayOfImageToUpload.count

                for i in 0..<count{
                    multipartFormData.append(arrayOfImageToUpload[i], withName: "morephoto[\(i)]", fileName: "photo\(i).jpeg" , mimeType: "image/jpeg")

                }
                for (key, value) in parameterrs {

                        multipartFormData.append((value as AnyObject).data(using: String.Encoding.utf8.rawValue)!, withName: key)
                }
                print(multipartFormData)
            }, to: url!) { (result) in

                    switch result {
                    case .success(let upload, _ , _):

                        upload.uploadProgress(closure: { (progress) in

                            print("uploding: \(progress.fractionCompleted)")
                        })

                        upload.responseJSON { response in

                        print(response.result.value!)

                    }

                case .failure(let encodingError):
                    print("failed")
                    print(encodingError)

                }
            }

}

Use arrayOfImageToUpload as a parameter. and call this method in class where you want to upload images.

MRizwan33
  • 2,723
  • 6
  • 31
  • 42
  • Thank you @MRizwan33. for answering. How to send other parameters ..? – Ram Jul 19 '18 at 11:52
  • like wise you are calling it before just add another param with name arrayOfImageToUpload. I have edited check it. – MRizwan33 Jul 19 '18 at 11:56
  • Hi @MRizwan, I am using your suggested code but i am getting one error, How to solve this error, "Cannot invoke 'append' with an argument list of type '(Any, withName: String, fileName: String, mimeType: String)'" – Ram Jul 19 '18 at 12:36
  • it means there is some change in method append with swift 4.0 and above try to find out more ways to write same method. – MRizwan33 Jul 19 '18 at 12:51
0

Use Below method to send multiple images with different parameters using Alamofire.

    func uplaodImages(_ url: String,parameters: Dictionary<String,AnyObject>?,imageDataArray:[UIImage], compBlock : @escaping completionBlock,failure : @escaping failureBlock)
{

    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 parameters! {
            if let data = value.data(using: String.Encoding.utf8.rawValue) {
                multipartFormData.append(data, withName: key)

            }
        }

        for i in 0..<imageDataArray.count{
            let imageData1 = UIImageJPEGRepresentation(imageDataArray[i], 1.0)!
            multipartFormData.append(imageData1, withName: "morephoto[\(i)]" , fileName: "photo" + String(i) + ".jpg", mimeType: "image/jpeg")
        }

    },
                     to: url,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)
                        }
    })


}
Daggarwal
  • 234
  • 1
  • 7
  • Hi @Daggarwal Thank you for answering, But i am getting struck in this line "if let data = value.data(using: String.Encoding.utf8.rawValue)", i am getting this error - "Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSCFNumber dataUsingEncoding:]: unrecognized selector sent to instance 0x60c000637320'" – Ram Jul 20 '18 at 07:01
0
func mulipartImageupload()
{
 doOnMain {
    Loading.sharedInstance.startloading()
}
let url = NSURL(string:"\(Constant.BaseURL)")
let request = NSMutableURLRequest(url: url! as URL)
request.httpMethod = "POST"
var headers = ["Content-Type":"application/x-www-form-urlencoded"]
let boundary = generateBoundaryString()
//define the multipart request type
request.setValue("multipart/form-data; boundary=\(boundary)", forHTTPHeaderField: "Content-Type")

if !GlobalClass.sharedInstance.getCustomerKey().isEmpty {
    headers = ["Accept-Language": "en",
               "Authorization" : "Token"]
}
request.allHTTPHeaderFields = headers
let image_data = productImage.jpeg(.lowest)
if(image_data == nil){
    return
}

let image_data1 = productImage1.jpeg(.lowest)
if(image_data1 == nil){
    return
}


let body = NSMutableData()
let fname = "parameter1"
let fname1 = "parameter2"
let mimetype = "image/png"
let parameters = dict



if parameters != nil {
    for (key, value) in parameters {
        body.append("--\(boundary)\r\n".data(using: String.Encoding.utf8)!)
        body.append("Content-Disposition: form-data; name=\"\(key)\"\r\n\r\n".data(using: String.Encoding.utf8)!)
        body.append("\(value)\r\n".data(using: String.Encoding.utf8)!)
    }
}
if isFrontImage == true {
    body.append("--\(boundary)\r\n".data(using: String.Encoding.utf8)!)
    body.append("Content-Disposition:form-data; name=\"test\"\r\n\r\n".data(using: String.Encoding.utf8)!)
    body.append("hi\r\n".data(using: String.Encoding.utf8)!)
    body.append("--\(boundary)\r\n".data(using: String.Encoding.utf8)!)
    body.append("Content-Disposition:form-data; name=\"parameter1\"; filename=\"\(fname)\"\r\n".data(using: String.Encoding.utf8)!)
    body.append("Content-Type: \(mimetype)\r\n\r\n".data(using: String.Encoding.utf8)!)
    body.append(image_data!)
}
if isBackImage == true {
    body.append("--\(boundary)\r\n".data(using: String.Encoding.utf8)!)
    body.append("Content-Disposition:form-data; name=\"test\"\r\n\r\n".data(using: String.Encoding.utf8)!)
    body.append("hi\r\n".data(using: String.Encoding.utf8)!)
    body.append("--\(boundary)\r\n".data(using: String.Encoding.utf8)!)
    body.append("Content-Disposition:form-data; name=\"parameter2\"; filename=\"\(fname1)\"\r\n".data(using: String.Encoding.utf8)!)
    body.append("Content-Type: \(mimetype)\r\n\r\n".data(using: String.Encoding.utf8)!)
    body.append(image_data1!)
}


body.append("\r\n".data(using: String.Encoding.utf8)!)
body.append("--\(boundary)--\r\n".data(using: String.Encoding.utf8)!)
request.httpBody = body as Data


let session = URLSession.shared
let task = session.dataTask(with: request as URLRequest) {
    (
        data, response, error) in
    guard let _:NSData = data! as NSData, let _:URLResponse = response, error == nil else {
        print("error")
        return
    }
    let responseString = NSString(data: data!, encoding: String.Encoding.utf8.rawValue)
    print("****** response data = \(responseString!)")
    do {
        let json = try JSONSerialization.jsonObject(with: data!, options: []) as? NSDictionary
        let dict = json?.value(forKey: "data") as? NSDictionary ?? [:]
        print("****** response json = \(json!)")
        
        if json?.value(forKeyPath: "status") as? Int == 200 {
            let dict = json?.value(forKey: "data") as? NSDictionary ?? [:]
            DispatchQueue.main.async {
                Loading.sharedInstance.stoploading()
                
                
            }
            
        }
        else{
            Loading.sharedInstance.stoploading()
          
        }
    }catch{
        print(error)
        Loading.sharedInstance.stoploading()
        
    }
}
task.resume()
}

func generateBoundaryString() -> String {
return "Boundary-\(NSUUID().uuidString)"
}

extension UIImage {
enum JPEGQuality: CGFloat {
    case lowest  = 0
    case low     = 0.25
    case medium  = 0.5
    case high    = 0.75
    case highest = 1
}

/// Returns the data for the specified image in JPEG format.
/// If the image object’s underlying image data has been purged, calling this function forces that data to be reloaded into memory.
/// - returns: A data object containing the JPEG data, or nil if there was a problem generating the data. This function may return nil if the image has no data or if the underlying CGImageRef contains data in an unsupported bitmap format.
func jpeg(_ jpegQuality: JPEGQuality) -> Data? {
    return jpegData(compressionQuality: jpegQuality.rawValue)
}
}
shan
  • 136
  • 7