Alamofire错误代码= -1000“URL不指向文件URL”
有问题从我正在开发的iOS应用程序上传图像到我的服务器。 我正在使用Alamofire和一个UIImagePickerController
。
在didFinishPickingMediaWithInfo
委托方法内我保存用户从名为self.imageNSURL
的variables中的info[UIImagePickerControllerReferenceURL]
select作为NSURL
的文件。
通过这个Alamofires上传multipartFormData方法(几乎是从他们的文档标准复制和粘贴)
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) } } )
我得到的错误是
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}
请注意,我已经在这个post的回应中修改了ID,实际的错误信息包含有效的信息。
那么这是由于从info[UIImagePickerControllerReferenceURL]
返回的URL这个URL指向资产库/资产,这是由于沙箱。 所以你不能使用这个URL访问这个文件,这就是为什么alamofire抱怨你的URL不是一个文件的URL。 为了解决这个问题,你可以使用multipartFormData.appendBodyPart(data: data, name: name)
这个方法把数据直接作为NSData
发送。 完整的代码示例:
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) } })
我之前遇到过这个问题。 幸运的是, Alamofire
有一个方法,必须明确上传一个.jpeg文件到你的服务器,这是有益的,因为它避免了把你的映像NSData
写到磁盘所需的时间。 这是通过multipartFormData.appendBodyPart(data: imageData, name: "image", fileName: "image.jpeg", mimeType: "image/jpeg")
。
下面是一个更详细的例子:
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) } })
我有与本地图像path相同的问题,并通过设置正确的path解决
实用function
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!") } }
请求
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 } } ) }