Error Alamofire Code = -1000 "La URL no apunta a una URL de file"

Tengo problemas para upload imágenes a mi server desde la aplicación iOS que estoy desarrollando. Estoy usando Alamofire y un UIImagePickerController .

Dentro del método de delegado didFinishPickingMediaWithInfo , estoy guardando el file que el usuario selecciona como un NSURL de la info[UIImagePickerControllerReferenceURL] en una variable llamada self.imageNSURL .

Pasando esto a Alamofires cargar el método multipartFormData como tal (prácticamente una copy y pegado estándar de sus documentos )

 Alamofire.upload( .POST, URLString: "http://app.staging.acme.com/api/users/\(id)/picture", multipartFormData: { multipartFormData in multipartFormData.appendBodyPart(fileURL: self.imageNSURL, name: "image") }, encodingCompletion: { encodingResult in switch encodingResult { case .Success(let upload, _, _): upload.responseJSON { request, response, JSON, error in println(JSON) } case .Failure(let encodingError): println(encodingError) } } ) 

El error a cambio que recibo es

 Error Domain=com.alamofire.error Code=-1000 "The operation couldn't be completed. The URL does not point to a file URL: assets-library://asset/asset.JPG?id=00000000-0000-0000-0000-000000000000&ext=JPG" UserInfo=0x00000000000 {NSLocalizedFailureReason=The URL does not point to a file URL: assets-library://asset/asset.JPG?id=00000000-0000-0000-0000-000000000000&ext=JPG} 

Tenga en count que he identificado las identificaciones en la respuesta de esta publicación, el post de error real contiene las válidas.

Bueno, esto se debe a la URL devuelta por la info[UIImagePickerControllerReferenceURL] esta URL apunta a assets-library / asset, esto debido al sandboxing. Por lo tanto, no puede acceder al file utilizando esta URL, por lo que alamofire se queja de que su URL no es una URL de file. Para resolver este problema puede utilizar multipartFormData.appendBodyPart(data: data, name: name) este método toma los datos para enviarlos directamente como NSData . Ejemplo de código completo:

 let imagePicked = info[UIImagePickerControllerOriginalImage] let imageExtenstion = info[UIImagePickerControllerReferenceURL] // imageExtenstion will be "asset.JPG"/"asset.JPEG"/"asset.PNG" // so we have to remove the asset. part var imagePickedData : NSData switch imageExtenstion { case "PNG": imagePickedData = UIImagePNGRepresentation(imagePicked)! // compressionQuality is a float between 0.0 and 1.0 with 0.0 being most compressed with lower quality and 1.0 least compressed with higher quality case "JPG", "JPEG": imagePickedData = UIImageJPEGRepresentation(image, compressionQuality)! } Alamofire.upload(.POST, YOUR_URL, multipartFormData: { multipartFormData in multipartFormData.appendBodyPart(data: imagePickedData, name: imageName) }, encodingCompletion: { encodingResult in switch encodingResult { case .Success(let upload, _, _): upload.responseJSON { request, response, JSON, error in print(JSON) } case .Failure(let encodingError): print(encodingError) } }) 

Me encontré con este mismo problema antes. Afortunadamente Alamofire tiene una forma de tener que cargar explícitamente un file .jpeg a su server, lo cual es beneficioso ya que evita el time requerido para escribir su image NSData en el disco. Esto se logra con multipartFormData.appendBodyPart(data: imageData, name: "image", fileName: "image.jpeg", mimeType: "image/jpeg") .

A continuación se muestra un ejemplo más detallado:

 Alamofire.upload(.POST, "path/to/resource/to/receive/image/", multipartFormData: { multipartFormData -> Void in /** - parameter imageData: NSData representation of your image - parameter name: String of the name to associated with the data in the Content-Disposition HTTP header. To use an HTML example, "image" in the following code: <input type="file" name="image"> - parameter fileName: String of the name that you are giving the image file, an example being image.jpeg - parameter mimeType: String of the type of file you are uploading (image/jpeg, image/png, etc) **/ multipartFormData.appendBodyPart(data: imageData, name: "image", fileName: "image.jpeg", mimeType: "image/jpeg") }, encodingCompletion: { encodingResult in switch encodingResult { case .Success(let upload, _, _): upload.responseJSON { response in debugPrint(response) } case .Failure(let encodingError): print(encodingError) } }) 

Tuve el mismo problema con la ruta de image local y se resolvió estableciendo la ruta correcta

Funciones de utilidad

 var TimestampJPGImageName :String { var stringTimeStamp = "\(NSDate().timeIntervalSince1970 * 1000)" stringTimeStamp = stringTimeStamp.stringByReplacingOccurrencesOfString(".", withString: "_") stringTimeStamp = stringTimeStamp.stringByAppendingString(".jpg") stringTimeStamp = stringTimeStamp.stringByAddingPercentEncodingWithAllowedCharacters( NSCharacterSet.URLQueryAllowedCharacterSet())! return stringTimeStamp } func fileUrlForPathComponent(pathComponent: String) -> NSURL?{ let pathDocumentDirectory = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)[0] as String let filePath = "\(pathDocumentDirectory)/\(pathComponent)" let fileUrl = NSURL(fileURLWithPath: filePath) return fileUrl } func fileSaveToDirectory(image: UIImage, name: String?) -> NSURL? { //let fileManager = NSFileManager.defaultManager() //fileManager.createFileAtPath(fileUrlToWrite!.path, contents: imageData, attributes: nil) var fileUrlToWrite : NSURL? = nil if let fileName : String = name { fileUrlToWrite = fileUrlForPathComponent(fileName)//.stringByAppendingString(".png") }else{ fileUrlToWrite = fileUrlForPathComponent(TimestampJPGImageName)//.stringByAppendingString(".png") } assert(fileUrlToWrite != nil, "please check filePath") if (fileUrlToWrite != nil){ let imageData: NSData = UIImageJPEGRepresentation(image, 0.6)! imageData.writeToFile(fileUrlToWrite!.path!, atomically: false) return fileUrlToWrite! } else{ return nil } } func fileRemoveAtURL(URL : NSURL) ->(success : Bool?, message : String?){ if let path : String = URL.path{ let fileManager = NSFileManager.defaultManager() do { try fileManager.removeItemAtPath(path) } catch let error as NSError { return (false, error.localizedDescription) } return (true, "file removed!") }else{ return (false, "invalid path!") } } 

Hacer un pedido

 func requestCreateEvent(){ if (canMakeAPIRequest() == false){ return } let imageJPEGname = TimestampJPGImageName var parameters : Dictionary<String, AnyObject> = ["event[eventName]" : configuration.stringEventName, "event[images][0][image][imageFile]" : self.imageTaken!, "event[images][0][image][imageName]" : imageJPEGname, ] var headers = [String:String]() headers["Content-Type"] = "multipart/form-data" let urlpath = URL_CreateEvent.stringByAppendingString("?access_token=\(gblConfiguration!.AppToken!.accessToken)") var arrayImageURL : Array<NSURL> = [] self.view.showLoader() Alamofire.upload(.POST, urlpath, headers: headers, multipartFormData: { (multipartFormData) -> Void in if let dictUpload : Dictionary<String, AnyObject> = parameters { for (key , value) in dictUpload { if value.isKindOfClass(UIImage) { if let image = value as? UIImage{ /* //Upload Image with Data if let imageData = UIImageJPEGRepresentation(image, 0.8) { multipartFormData.appendBodyPart(data: imageData, name: key, fileName: imageJPEGname, mimeType: "image/jpg") }else if let imageData = UIImagePNGRepresentation(image) { multipartFormData.appendBodyPart(data: imageData, name: key, fileName: "myImage.png", mimeType: "image/png") }*/ //Upload Image with URL PATH if let fileURL : NSURL = fileSaveToDirectory(image, name: imageJPEGname) { multipartFormData.appendBodyPart(fileURL: fileURL , name: key) arrayImageURL.append(fileURL) } else { assert(false, "Unable to save file-name \(imageJPEGname)") } } } else { multipartFormData.appendBodyPart(data: "\(value)".dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)!, name: key) } } } }, encodingMemoryThreshold: Manager.MultipartFormDataEncodingMemoryThreshold, encodingCompletion:{ encodingResult in switch encodingResult { case .Success(let request, let _, let _): request.responseJSON { response in //debugPrint(response) self.view.hideLoader() if let objResponse : NSHTTPURLResponse = response.response { if objResponse.statusCode == 201 { //SUCCESS STATUS for url : NSURL in arrayImageURL { fileRemoveAtURL(url) } let alert = UIAlertView.init(title: AppName, message: "Event Created!", delegate: nil , cancelButtonTitle: "OK") alert.show() self.navigationController?.popToRootViewControllerAnimated(true) } else if objResponse.statusCode == 500 { let alert = UIAlertView.init(title: AppName, message: "Bad access", delegate: nil , cancelButtonTitle: "OK") alert.show() } } switch response.result { case .Success(let JSON): // Error Handling if let responseDictionary = JSON as? NSDictionary { if let errors = responseDictionary["errors"] { if let _ = errors["errors"] as? Array<String> { showErrorMessageAlertView(errors, viewdelegate: self) } } else if let error = responseDictionary["error"] as? String, let errorDescription = responseDictionary["error_description"] as? String { let alert = UIAlertView.init(title: error, message: errorDescription, delegate: nil , cancelButtonTitle: "OK") alert.show() } } case .Failure(let error): print("Request failed with error: \(error)") } } break case .Failure(let encodingError as NSError): print(encodingError) self.view.hideLoader() showErrorMessageAlertView(encodingError, viewdelegate: nil) break default : self.view.hideLoader() break } } ) }