如何在 Swift 4 中使用 Alamofire 上传具有其他参数的多个图像

Posted

技术标签:

【中文标题】如何在 Swift 4 中使用 Alamofire 上传具有其他参数的多个图像【英文标题】:How to upload multiple images with other parameters using Alamofire in Swift 4 【发布时间】:2018-07-19 10:56:05 【问题描述】:

我正在使用Alamofire 向服务器发送请求。现在我必须使用其他参数将一组图像(多个图像)发送到服务器。我必须发送最多 4 张图片。请有人帮助我,如何解决这个任务。我检查了 *** 的解决方案,但所有解决方案都类似于将单个图像发送到服务器。但我想使用Alamofire 发送多个图像,因为我有图像数组。

这是我的代码

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")
                                
            )
        
    

我在这一行遇到一个错误

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

我认为它只需要字符串参数,但我同时拥有 String 和 NSNumber。所以这是我的问题,如何对值字符串和 NSNumber 进行编码。请有人帮助/建议我。

【问题讨论】:

您可以发布您尝试过的代码示例吗? 这可能会帮助你***.com/questions/49230181/… 对多个图像使用github.com/hyperoslo/ImagePicker,并将其作为字符串传递给参数 是的@DilipTiwari 我会检查 如果有任何帮助请求让我知道我已经在使用上面的链接并使用多个图像数组发送多个参数 【参考方案1】:

使用此方法在服务器上上传图像数组。 (如果您的服务器接受它们)。

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)

                
            

使用 arrayOfImageToUpload 作为参数。并在要上传图片的类中调用此方法。

【讨论】:

谢谢@MRizwan33。为回答。如何发送其他参数..? 在添加另一个名为 arrayOfImageToUpload 的参数之前调用它。我已经编辑检查它。 嗨@MRizwan,我正在使用您建议的代码,但出现一个错误,如何解决此错误,“无法使用类型为'的参数列表调用'附加'(任何,withName:字符串,文件名:字符串,mimeType:字符串)'" 这意味着在 swift 4.0 及以上版本中追加的方法有一些变化,尝试找出更多方法来编写相同的方法。【参考方案2】:

使用以下方法使用 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 谢谢你的回答,但我在这行“if let data = value.data(using: String.Encoding.utf8.rawValue)”中感到震惊,我收到了这个错误-“由于未捕获的异常'NSInvalidArgumentException'而终止应用程序,原因:'-[__NSCFNumber dataUsingEncoding:]:无法识别的选择器发送到实例0x60c000637320'”【参考方案3】:
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)


【讨论】:

以上是关于如何在 Swift 4 中使用 Alamofire 上传具有其他参数的多个图像的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Swift 4 中使用 Alamofire 上传具有其他参数的多个图像

Alamofire 4 请求返回 NSArray,无法弄清楚如何在 Swift 3 中使用 SwiftyJSON 进行解析

如何使用 Alamofire Swift 4 在 JSON 编码中传递数据

如何使用 Alamofire,Swift 4 为 UICollectionView 获取 JSON 数据

如何在 Alamofire 4.0 中仅使用参数和正文在 swift 中使用 POST 方法发送请求?

如何使用参数 swift 3.0 Alamofire 4.0 调用邮政服务?