深谙iOS网络编程之Http NSURLSession(下)

革码者基地

1.前言

  • 此文章将记录Http请求之NSURLSession用法。至于什么是Http,可参考深谙iOS网络编程之Http真相揭秘(上)
  • 由于在iOS9.0之后,NSURLConnection被废弃,苹果推荐使用NSURLSession来替换NSURLConnection完成网路请求相关操作,所以本文不再涉及NSURLConnection用法。

2.NSURLSession

简单:NSURLSession的使用非常简单,先根据会话对象创建一个请求Task,然后执行该Task即可。

抽象:NSURLSessionTask本身是一个抽象类,在使用的时候,通常是根据具体的需求使用它的几个子类。关系如下:

革码者基地

一、发送GET请求
  使用NSURLSession发送GET请求的方法整个过程如下:
    1)确定请求路径,GET请求参数直接跟在URL后面
    2)创建请求对象(默认包含了请求头和请求方法【GET】),可配置
    3)创建会话对象(NSURLSession),可配置
    4)根据会话对象创建请求任务(NSURLSessionDataTask)
    5)执行Task
    6)当得到服务器返回的响应后,解析数据(XML|JSON|HTTP)

//普通的HTTP get请求
    func getRequest(){
        // 获取Url --- 这个是我获取的天气预报接口
        let url:NSURL = NSURL(string: "http://aqicn.org/publishingdata/json")!
        // 转换为requset
        let requets:NSURLRequest = NSURLRequest(URL: url)
        //NSURLSession 对象都由一个 NSURLSessionConfiguration 对象来进行初始化,后者指定了刚才提到的那些策略以及一些用来增强移动设备上性能的新选项
        let configuration:NSURLSessionConfiguration = NSURLSessionConfiguration.defaultSessionConfiguration()

        //backgroundSessionConfigurationWithIdentifier 后台处理配置
        //ephemeralSessionConfiguration 这个是基于RAM的方式处理配置,数据时临时性的
        //defaultSessionConfiguration 这个是默认配置

        let session:NSURLSession = NSURLSession(configuration: configuration)
        
        //NSURLSessionTask负责处理数据的加载以及文件和数据在客户端与服务端之间的上传和下载,NSURLSessionTask 与 NSURLConnection 最大的相似之处在于它也负责数据的加载,最大的不同之处在于所有的 task 共享其创造者 NSURLSession 这一公共委托者(common delegate)
        let task:NSURLSessionDataTask = session.dataTaskWithRequest(requets, completionHandler: {
            (data:NSData?,response:NSURLResponse?,error:NSError?)->Void in
            if error == nil{
                do{                    
                    let responseData = try NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.AllowFragments) as! NSArray       
                    print(responseData)
                    dispatch_async(dispatch_get_main_queue(), { () -> Void in
                        self.dataLabel.text = responseData.firstObject!["cityName"]! as? String
                    })                    
                }catch{
                    
                }
            }
        })
        // 启动任务
        task.resume()
    }
//带header的HTTP get 请求
    @IBAction func getRequestWithHeader(sender: AnyObject) {
        
        let url:NSURL = NSURL(string: "http://apis.baidu.com/heweather/pro/weather?city=beijing")!
        
        let request:NSMutableURLRequest = NSMutableURLRequest(URL:url)
        
        request.HTTPMethod = "GET"
        // 请求的Header
        request.addValue("a566eb03378211f7dc9ff15ca78c2d93", forHTTPHeaderField: "apikey")
        
        let configuration:NSURLSessionConfiguration = NSURLSessionConfiguration.defaultSessionConfiguration()
        let session:NSURLSession = NSURLSession(configuration: configuration)

        let task:NSURLSessionDataTask = session.dataTaskWithRequest(request, completionHandler: {
            (data:NSData?,response:NSURLResponse?,error:NSError?)->Void in
            if error == nil{
                do{
                    let responseData:NSDictionary = try NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.AllowFragments) as! NSDictionary
                    print("普通带头与参数的GET请求 --- > \(responseData)")
                    
                }catch{
                    
                }
            }
        })
        task.resume()
    }
//get请求实战应用:写入文件。
    override func viewDidLoad() {
        super.viewDidLoad()
        //let config = NSURLSessionConfiguration.backgroundSessionConfiguration("back")//不赞成使用
        //let config = NSURLSessionConfiguration.backgroundSessionConfigurationWithIdentifier("back")//委托中不能使用,使用系统处理下载,就算APP没有运行了,也可以实现
        //let config = NSURLSessionConfiguration.ephemeralSessionConfiguration();//这个是临时数据下载,适用于小数据下载
       
        let config = NSURLSessionConfiguration.defaultSessionConfiguration()//默认配置
        config.timeoutIntervalForRequest = 15 //连接超时时间
        
        session = NSURLSession(configuration: config, delegate: self, delegateQueue:nil)//队列中,如果想要程序在主线程中执行,可以使用NSOperationQueue.mainQueue()
        
        let url = NSURL(string: "http://www.jianshu.com/p/e89f4b40bd85")
        let task = session.dataTaskWithURL(url!) { (data, response, error) -> Void in
            if (error == nil){
                
                let str = NSString(data: data!, encoding: NSUTF8StringEncoding)
                print("Done!")
               
                self.session.finishTasksAndInvalidate() //确保执行完成后,释放session
   
                let manager = NSFileManager.defaultManager()                
                do{
                    var destinationPath = try manager.URLForDirectory(.CachesDirectory, inDomain: .UserDomainMask, appropriateForURL: url, create: true)
                    
//                    获取//符号后面的string
                    let componenetsOfUrl = url?.absoluteString.componentsSeparatedByString("/")
                    let index = componenetsOfUrl!.count - 1
                    let fileNameFromUrl = componenetsOfUrl![index]+".text"
                    
                    destinationPath = destinationPath.URLByAppendingPathComponent(fileNameFromUrl)                    
                    try str?.writeToURL(destinationPath, atomically: true, encoding: NSUTF8StringEncoding)
                    let message = "保存下载数据到 = \(destinationPath)"             
                    self.displayAlertWithTitle("Success", message: message)
                    print(message)
                }catch{
                   print("error")
                }             
            }else{
                self.displayAlertWithTitle("Error", message: "不能下载这数据,一个错误抛出")
            }
        }
        task.resume()       
    }
   
    func displayAlertWithTitle(title:String,message:String){        
        let controller = UIAlertController(title: title, message: message, preferredStyle: UIAlertControllerStyle.Alert)
        controller.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.Default, handler: nil))
        presentViewController(controller, animated: true, completion: nil)
    }
//get请求实战应用:后台下载处理
import UIKit

extension NSURLSessionTask{
    func start(){
        self.resume()
    }
}

class ViewController3:UIViewController,NSURLSessionDelegate,NSURLSessionDownloadDelegate,NSURLSessionTaskDelegate {
    
    var session:NSURLSession!
    
    var configidentifier:String{
        
        let userDefaults:NSUserDefaults = NSUserDefaults.standardUserDefaults()
        let key  = "time"
        
        let times = userDefaults.stringForKey(key)
        
        if let thetime = times {
            return thetime
        }else{
            let newtime = NSDate().description
            userDefaults.setObject(newtime, forKey: key)
            userDefaults.synchronize()
            return newtime
        }
    }
    
  
    required init(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)!
    }
   
    
    override func viewDidAppear(animated: Bool) {
        
        super.viewDidAppear(animated)
        
        let config = NSURLSessionConfiguration.backgroundSessionConfigurationWithIdentifier(self.configidentifier)
        config.timeoutIntervalForRequest = 15
        
        session = NSURLSession(configuration: config, delegate: self, delegateQueue: nil)
        
        let url = NSURL(string: "http://www.jianshu.com/p/e89f4b40bd85")
        
        let task = session.downloadTaskWithURL(url!)
        
        task.start()
        
    }
    
    func URLSession(session: NSURLSession, downloadTask: NSURLSessionDownloadTask, didWriteData bytesWritten: Int64, totalBytesWritten: Int64, totalBytesExpectedToWrite: Int64) {
        print(downloadTask.response)
        let progress = totalBytesWritten / totalBytesExpectedToWrite
        print(bytesWritten)
        print(totalBytesWritten)
        print(totalBytesExpectedToWrite)//如果服务器未返回总长度,这里就显示-1
        print(progress)
        NSLog("接收数据")
       
    }
    
    func URLSession(session: NSURLSession, downloadTask: NSURLSessionDownloadTask, didFinishDownloadingToURL location: NSURL) {
        do{
           
            // 将临时文件剪切或者复制其他文件夹才能看到
           let fileManager = NSFileManager.defaultManager()
           let cachePath = try fileManager.URLForDirectory(.CachesDirectory, inDomain: .UserDomainMask, appropriateForURL: nil, create: true)
           let saveFileName = (cachePath.path)! + "/" + (downloadTask.response?.suggestedFilename)!
           try fileManager.moveItemAtPath(location.path!, toPath: saveFileName)
           NSLog("下载完成")
        }catch{
            
        }
    }
    
    
    func URLSession(session: NSURLSession, task: NSURLSessionTask, didCompleteWithError error: NSError?) {
        
        NSLog("任务完成")
        
        session.finishTasksAndInvalidate()
    }

二、发送POST请求
    使用NSURLSession发送POST请求的方法整个过程如下:
    1)确定请求路径(一般由公司的后台开发人员以接口文档的方式提供)
    2)创建可变的请求对象(因为需要修改),此步骤不可以省略
    3)修改请求方法为POST
    4)设置请求体,把参数转换为二进制数据并设置请求体
    5)创建会话对象(NSURLSession)
    6)根据会话对象创建请求任务(NSURLSessionDataTask)
    7)执行Task
    8)当得到服务器返回的响应后,解析数据(XML|JSON|HTTP)

//普通的HTTP Post请求
    func postRequest(){
        let request = NSMutableURLRequest(URL: NSURL(string: "http://120.25.226.186:32812/login")!)
        // 这块就是区别啦,其实也差不多
        request.HTTPMethod = "POST"
        let postString = "username=520it&pwd=520it&type=JSON"
        request.HTTPBody = postString.dataUsingEncoding(NSUTF8StringEncoding)
        
        let task = NSURLSession.sharedSession().dataTaskWithRequest(request, completionHandler: {
            (data:NSData?,response:NSURLResponse?,error:NSError?)->Void in
            if error == nil{
                do{
//解析方式1
                    let responseString = try NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.AllowFragments) as! NSDictionary
                 
                     print("Post --- > \(responseString)")
                    let result = responseString["success"]?.dataUsingEncoding(NSUTF8StringEncoding)
                    let result1 = NSString(data: result!, encoding:NSUTF8StringEncoding )
                    print(result1)
// 解析方式2
                    let responseString2 = NSString(data: data!, encoding: NSUTF8StringEncoding)
                    print("Post --- > \(responseString2)")
                }catch{
                    print("have catch")
                }
            }    
        })
        task.resume()
    }
//post请求实战应用:上传
class ViewController4:UIViewController,NSURLSessionDelegate,NSURLSessionDataDelegate{ 
    var session:NSURLSession!    
    func displayAlertWithTitle(title:String,message:String){        
        let controller:UIAlertController = UIAlertController(title: title, message: message, preferredStyle: UIAlertControllerStyle.Alert)        
        controller.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.Default, handler: nil))        
        presentViewController(controller, animated: true, completion: nil)
    } 
    required init(coder aDecoder: NSCoder) {       
        super.init(coder: aDecoder)!
    }
 
    override func viewDidAppear(animated: Bool) {
        super.viewDidAppear(animated)
        
        
        let config = NSURLSessionConfiguration.defaultSessionConfiguration()
        config.timeoutIntervalForRequest  = 15
        
        session = NSURLSession(configuration: config, delegate: self, delegateQueue: nil)
        let datatoup = "Hello World".dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)
        
        let url = NSURL(string: "http://www.jianshu.com/p/e89f4b40bd85")
        
        let request = NSMutableURLRequest(URL: url!)
        
        request.HTTPMethod = "POST"
        
        let task = session.uploadTaskWithRequest(request, fromData: datatoup!)
        
        task.start()
        
    }
    
    
    func URLSession(session: NSURLSession, task: NSURLSessionTask, didCompleteWithError error: NSError?) {
        
        session.finishTasksAndInvalidate()
        
        NSLog("错误 = \(error)")
        
        
        dispatch_async(dispatch_get_main_queue(), {[weak self] () -> Void in
            
            var message = "完成上传数据"
            
            if error != nil {
                message = "上传内容失败"
            }            
            self?.displayAlertWithTitle("信息", message: message)            
            })        
    }    
}

至此,文章已经记录了HTTP中的GET和POST请求的基本应用。希望对学习网络编程的码儿有所帮助。

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

推荐阅读更多精彩内容