由于之前一直在忙項目,很久沒有寫過一篇像樣的文章了,現在手上的項目基本是完成了,正好工作時間偷個懶寫兩篇文章。
將相機或相冊圖片上傳到服務器
先看看最常見的圖片上傳,也可以選擇跳過,后面有直接的封裝方法
在實際開發中,圖片上傳是很常見的功能,比如和朋友圈一樣發布一條動態要添加幾張圖片,或者上傳用戶頭像什么的,這里就介紹如何通過第三方庫Alamofire進行圖片上傳(這里使用的是Swift,下文更新了Swift3、Alamofire4.5.0的代碼版本,OC可以用AFNetworking)。
當我們上傳圖片通常還需要帶參數,Alamofire不像AF一樣具有封裝好的帶參數上傳圖片的方法,但是可以通過其他方法拼接參數,代碼中會有相應注釋。
如下圖,我已經寫好了調用相機和相冊的界面,如果不會使用相機相冊,請看我之前寫過的一篇文章:http://www.lxweimin.com/p/ab98f2fe2734
我分別給取消按鈕,拍照按鈕,相冊按鈕設置了tag值,對應的點擊方法如下(changeView是上圖所示的灰色透明界面以及灰色界面上層界面):
func buttonClickedAction(sender: UIButton) {
switch sender.tag {
case 204:
//取消點擊
changeView.removeFromSuperview()
case 205:
//拍照點擊
changeView.removeFromSuperview()
if UIImagePickerController.isSourceTypeAvailable(.Camera) {
let picker = UIImagePickerController()
picker.sourceType = .Camera
picker.delegate = self
picker.allowsEditing = true
self.presentViewController(picker, animated: true, completion: nil)
}
else
{
self.noticeOnlyText("無法使用相機", autoClear: true, autoClearTime: 1)
}
case 206:
//相冊點擊
//調用相冊功能,打開相冊
changeView.removeFromSuperview()
let picker = UIImagePickerController()
picker.sourceType = .PhotoLibrary
picker.delegate = self
picker.allowsEditing = true
self.presentViewController(picker, animated: true, completion: nil)
default:
break
}
}
做了上述點擊事件后,點擊相機拍照后或者相冊進行選擇后就可得到照片選擇器
選擇完成我們就可以用相機協議(UIImagePickerControllerDelegate,UINavigationControllerDelegate)中的imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : AnyObject])方法獲取圖片
下面的內容就直接在代碼中解釋:
func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : AnyObject]) {
//獲取info的類型
let type: String = (info[UIImagePickerControllerMediaType] as! String)
//如果選擇的類型是圖片
if type == "public.image"
{
//修正圖片的位置(因為有時候上傳的圖片有顛倒,所以要修正一下,方法在后面)
let image = self.fixOrientation((info[UIImagePickerControllerOriginalImage] as! UIImage))
//****************保存圖片到本地
//先把圖片轉成NSData(這里壓縮圖片到0.5,圖片過大會造成上傳時間太久或失敗)
let data = UIImageJPEGRepresentation(image, 0.5)
//Home目錄
let homeDirectory = NSHomeDirectory()
let documentPath = homeDirectory + "/Documents"
//文件管理器
let fileManager: NSFileManager = NSFileManager.defaultManager()
//把剛剛圖片轉換的data對象拷貝至沙盒中 并保存為image.png
do {
try fileManager.createDirectoryAtPath(documentPath, withIntermediateDirectories: true, attributes: nil)
}
catch let error {
print(error)
}
fileManager.createFileAtPath(documentPath.stringByAppendingString("/image.png"), contents: data, attributes: nil)
//得到選擇后沙盒中圖片的完整路徑
let filePath: String = String(format: "%@%@", documentPath, "/image.png")
// print("filePath:" + filePath)
//開始上傳圖片
pleaseWait()
//upLoadImageURL:上傳地址
Alamofire.upload(.POST, upLoadImageURL , multipartFormData: { multipartFormData in
let lastData = NSData(contentsOfFile: filePath)
//圖片二進制作為參數值,file作為參數名(參數名必須與后臺一致)
multipartFormData.appendBodyPart(data: lastData!, name: "file", fileName: "image.png", mimeType: "image/png")
//拼接其他參數(可以拼接多個參數,我這里需要傳一個user_id的參數)
multipartFormData.appendBodyPart(data: crrentUser!.user_id.dataUsingEncoding(NSUTF8StringEncoding)!, name: "user_id" )
}, encodingCompletion: { response in
//讓選擇器消失掉
picker.dismissViewControllerAnimated(true, completion: nil)
switch response {
case .Success(let upload, _, _):
upload.responseJSON(completionHandler: { (response) in
self.clearAllNotice()
if let json = response.result.value{
let code = json.objectForKey("code") as! String
// print(code)
//我這里上傳成功后后臺會返回code=200
if code == "200"{
self.headImageView.image = UIImage(data: data!)
let data = json.objectForKey("data") as! String
crrentUser!.head_img = data
}
}
})
case .Failure(let encodingError):
print(encodingError)
}
})
}
}
func fixOrientation(aImage: UIImage) -> UIImage {
// No-op if the orientation is already correct
if aImage.imageOrientation == .Up {
return aImage
}
// We need to calculate the proper transformation to make the image upright.
// We do it in 2 steps: Rotate if Left/Right/Down, and then flip if Mirrored.
var transform: CGAffineTransform = CGAffineTransformIdentity
switch aImage.imageOrientation {
case .Down, .DownMirrored:
transform = CGAffineTransformTranslate(transform, aImage.size.width, aImage.size.height)
transform = CGAffineTransformRotate(transform, CGFloat(M_PI))
case .Left, .LeftMirrored:
transform = CGAffineTransformTranslate(transform, aImage.size.width, 0)
transform = CGAffineTransformRotate(transform, CGFloat(M_PI_2))
case .Right, .RightMirrored:
transform = CGAffineTransformTranslate(transform, 0, aImage.size.height)
transform = CGAffineTransformRotate(transform, CGFloat(-M_PI_2))
default:
break
}
switch aImage.imageOrientation {
case .UpMirrored, .DownMirrored:
transform = CGAffineTransformTranslate(transform, aImage.size.width, 0)
transform = CGAffineTransformScale(transform, -1, 1)
case .LeftMirrored, .RightMirrored:
transform = CGAffineTransformTranslate(transform, aImage.size.height, 0)
transform = CGAffineTransformScale(transform, -1, 1)
default:
break
}
// Now we draw the underlying CGImage into a new context, applying the transform
// calculated above.
//這里需要注意下CGImageGetBitmapInfo,它的類型是Int32的,CGImageGetBitmapInfo(aImage.CGImage).rawValue,這樣寫才不會報錯
let ctx: CGContextRef = CGBitmapContextCreate(nil, Int(aImage.size.width), Int(aImage.size.height), CGImageGetBitsPerComponent(aImage.CGImage), 0, CGImageGetColorSpace(aImage.CGImage), CGImageGetBitmapInfo(aImage.CGImage).rawValue)!
CGContextConcatCTM(ctx, transform)
switch aImage.imageOrientation {
case .Left, .LeftMirrored, .Right, .RightMirrored:
// Grr...
CGContextDrawImage(ctx, CGRectMake(0, 0, aImage.size.height, aImage.size.width), aImage.CGImage)
default:
CGContextDrawImage(ctx, CGRectMake(0, 0, aImage.size.width, aImage.size.height), aImage.CGImage)
}
// And now we just create a new UIImage from the drawing context
let cgimg: CGImageRef = CGBitmapContextCreateImage(ctx)!
let img: UIImage = UIImage(CGImage: cgimg)
return img
}
將各種類型文件上傳服務器封裝
Swift3后Alamofire也更新了,下面是用Alamofire4.5.0版本封裝的,拷貝即可使用
import UIKit
import Alamofire
enum tbUploadType: String {
///純文本
case textOnly = "text/plain"
///HTML文檔
case html = "text/html"
///XHTML文檔
case xhtml = "application/xhtml+xml"
///gif圖片
case gif = "image/gif"
///jpeg圖片
case jpeg = "image/jpeg"
///png圖片
case png = "image/png"
///mpeg動畫
case mpeg = "video/mpeg"
///任意的二進制數據
case any = "application/octet-stream"
///PDF文檔
case pdf = "application/pdf"
///Word文件
case word = "application/msword"
///RFC 822形式
case rfc822 = "message/rfc822"
///HTML郵件的HTML形式和純文本形式,相同內容使用不同形式表示
case alternative = "multipart/alternative"
///使用HTTP的POST方法提交的表單
case urlencoded = "application/x-www-form-urlencoded"
///使用HTTP的POST方法提交的表單,但主要用于表單提交時伴隨文件上傳的場合
case formdata = "multipart/form-data"
}
class TBUploadDataManager: NSObject {
public static let share = TBUploadDataManager()
private override init() {}
/// 上傳文件
///
/// - Parameters:
/// - data: 二進制流
/// - parameters: 參數字典數組
/// - hostUrl: 服務器地址
/// - withName: 與后臺協商的名字
/// - fileName: 文件名
/// - type: 上傳文件類型
/// - comparBlock: 將結果返回的閉包
public func uploadLocalData(data: Data,
parameters:[String:String]?,
hostUrl:String,
withName:String,
fileName: String,
type:tbUploadType,
comparBlock:@escaping (SessionManager.MultipartFormDataEncodingResult) -> Void){
Alamofire.upload(
multipartFormData: { multipartFormData in
multipartFormData.append(data, withName: withName, fileName: fileName, mimeType: type.rawValue)
if parameters != nil{
for parameter in parameters!{
multipartFormData.append(parameter.value.data(using: .utf8)!, withName: parameter.key)
}
}
},
to: hostUrl,
encodingCompletion: { encodingResult in
//把encodingResult返回出去
comparBlock(encodingResult)
}
)
}
}
調用方法
let imagedata = UIImagePNGRepresentation(UIImage(named: "1111")!)
TBUploadDataManager.share.uploadLocalData(data: imagedata!, parameters: ["id":"12345"], hostUrl: "地址", withName: "協商名字", fileName: "1111.png", type: tbUploadType.png, comparBlock: { encodingResult in
switch encodingResult {
case .success(let upload, _, _):
upload.responseJSON { response in
debugPrint(response)
if let json = response.result.value{
print(json)
}
//
//成功要干什么
}
case .failure(let encodingError):
print(encodingError)
//失敗要干什么
}
})