在我正在开发的iOS应用程序中将图像上传到我的服务器时出现问题。我使用的是Alamofire和UIImagePickerController
。
在didFinishPickingMediaWithInfo
委托方法中,我保存用户从名为NSURL
的变量info[UIImagePickerControllerReferenceURL]
中选择self.imageNSURL
的文件。
将此传递给Alamofires就这样上传了multipartFormData方法(几乎是标准的副本并从他们的docs粘贴)
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}
请注意,我在此帖子的回复中已经识别了ID,实际的错误消息包含有效的消息。
答案 0 :(得分:3)
这是因为从info[UIImagePickerControllerReferenceURL]
返回的网址此URL指向资产库/资产,这归功于沙盒。因此,您无法使用此URL访问该文件,这就是为什么alamofire会抱怨您的网址不是文件网址的原因。要解决此问题,您可以使用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)
}
})
答案 1 :(得分:0)
之前我遇到过同样的问题。幸运的是,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)
}
})
答案 2 :(得分:0)
我对本地图像路径有同样的问题&amp;通过设置正确的路径来解决
效用函数
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
}
}
)
}