Swift3一行代码将各种类型文件上传到服务器

由于之前一直在忙项目,很久没有写过一篇像样的文章了,现在手上的项目基本是完成了,正好工作时间偷个懒写两篇文章。

将相机或相册图片上传到服务器

    先看看最常见的图片上传,也可以选择跳过,后面有直接的封装方法

在实际开发中,图片上传是很常见的功能,比如和朋友圈一样发布一条动态要添加几张图片,或者上传用户头像什么的,这里就介绍如何通过第三方库Alamofire进行图片上传(这里使用的是Swift,下文更新了Swift3、Alamofire4.5.0的代码版本,OC可以用AFNetworking)。
  当我们上传图片通常还需要带参数,Alamofire不像AF一样具有封装好的带参数上传图片的方法,但是可以通过其他方法拼接参数,代码中会有相应注释。

如下图,我已经写好了调用相机和相册的界面,如果不会使用相机相册,请看我之前写过的一篇文章://www.greatytc.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)
                //失败要干什么
            }
        })
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,193评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,306评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,130评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,110评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,118评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,085评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,007评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,844评论 0 273
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,283评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,508评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,667评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,395评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,985评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,630评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,797评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,653评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,553评论 2 352

推荐阅读更多精彩内容

  • 发现 关注 消息 iOS 第三方库、插件、知名博客总结 作者大灰狼的小绵羊哥哥关注 2017.06.26 09:4...
    肇东周阅读 12,092评论 4 62
  • 因为要结局swift3.0中引用snapKit的问题,看到一篇介绍Xcode8,swift3变化的文章,觉得很详细...
    uniapp阅读 4,412评论 0 12
  • 「逻辑思维」正式卖书之后,我就再也没买过它推荐的书。不过,最近却看了一套逻辑思维出品的《金圣叹批评本水浒》,这是一...
    王安迪阅读 785评论 1 5
  • 忽然下起暴雨 空气中弥漫着青草和泥土的味道 忽然想家 下起大雨,然后湿漉漉的跑回家,换上干净的衣服,冲个热水澡 然...
    风滚草yj阅读 201评论 0 1