NSURLSession,是IOS中一种封装性的网络请求功能(当然是我的理解),他以委托的形式来处理相关的网络请求,我们从几个方面来看看他的请求形式.
1.基本的网络请求
2.数据接收处理
3.后台处理请求
4.上传数据请求
基本的网络请求,通过NSURLSession来处理最简单的网络请求,首先是通过NSURLSessionConfiguration来创建基本的请求配置.这里有三种方式创建
backgroundSessionConfigurationWithIdentifier 后台处理配置
ephemeralSessionConfiguration 这个是基于RAM的方式处理配置,数据时临时性的
defaultSessionConfiguration 这个是默认配置
创建好配置后,我们通过timeoutIntervalForRequest来处理连接超时的情况,这个时间可以自己随自己的需求设定,我一般是设定在20s左右,然后通过NSURLSession的构造函数,来创建session,将处理委托给本身这个类,当然自己也可以重新创建一个新类来处理.接着就是调用dataTaskWithURL来处理请求,记得在请求处理完后,释放session,这里调用finishTashsAndInvalidate这个方法.在下面的代码里面我们通过NSFileManager来讲数据保存在缓存目录下.
在类中我们创建了displayAlertWithTitle方法,这个主要是用来弹出显示请求数据的(弹出框的简单应用),最后调用resume方法,执行请求操作.
import UIKit class ViewController: UIViewController,NSURLSessionDelegate,NSURLSessionDataDelegate { var session:NSURLSession! override func viewDidLoad() { super.viewDidLoad() //let config = NSURLSessionConfiguration.backgroundSessionConfiguration("back")//不赞成使用 //let config = NSURLSessionConfiguration.backgroundSessionConfigurationWithIdentifier("back")//委托中不能使用,使用系统处理下载,就算APP没有运行了,也可以实现 //let config = NSURLSessionConfiguration.ephemeralSessionConfiguration(, 0, 0);//这个是临时数据下载,适用于小数据下载 let config = NSURLSessionConfiguration.defaultSessionConfiguration()//默认配置 config.timeoutIntervalForRequest = 15 //连接超时时间 session = NSURLSession(configuration: config, delegate: self, delegateQueue:nil)//队列中,如果想要程序在主线程中执行,可以使用NSOperationQueue.mainQueue() let url = NSURL(string: "http://www.wutongwei.com") let task = session.dataTaskWithURL(url!, completionHandler: { ( data, response, error) -> Void in let str = NSString(data: data, encoding: NSUTF8StringEncoding) println("Done!") self.session.finishTasksAndInvalidate() //确保执行完成后,释放session if error == nil { let manager = NSFileManager() // var error:NSError? var destinationPath = manager.URLForDirectory(NSSearchPathDirectory.CachesDirectory, inDomain: NSSearchPathDomainMask.UserDomainMask, appropriateForURL: url, create: true, error: &error)! // let componenetsOfUrl = url?.absoluteString!.componentsSeparatedByString("/") let index = componenetsOfUrl!.count - 1 let fileNameFromUrl = componenetsOfUrl![index] destinationPath = destinationPath.URLByAppendingPathComponent(fileNameFromUrl) // manager.moveItemAtURL(url!, toURL: destinationPath, error: nil) let message = "保存下载数据到 = \(destinationPath)" self.displayAlertWithTitle("Success", message: message) }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) } /// override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() // Dispose of any resources that can be recreated. } }
下面我们来通过委托形式处理数据,主要是实现委托协议的一些相关方法.这里我们实现了两个URLSession方法包含参数didReceiveData和另外一个包含参数didCompleteWithError
didReceiveData 处理请求时的数据,我们在类中定义了NSMutableData类型的变量,这个变量主要用来接收didReceiveData这个方法传递过来的数据
didCompleteWithError 在处理完请求后响应的事件.
在这里在说明两个方法didReceiveData和didReceiveResponse,两个只能存在一个,didReceiveResponse高于didReceiveData,前者有的话,后者就不能执行
import UIKit class ViewController2:UIViewController,NSURLSessionDelegate,NSURLSessionDataDelegate{ var mutableData:NSMutableData = NSMutableData() var session:NSURLSession? override init() { super.init() let config = NSURLSessionConfiguration.defaultSessionConfiguration() session = NSURLSession(configuration: config, delegate: self, delegateQueue: nil) } override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?) { super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil) } required init(coder aDecoder: NSCoder) { super.init(coder: aDecoder) } override func viewDidAppear(animated: Bool) { let url:NSURL? = NSURL(string: "http://www.wutongwei.com") let task:NSURLSessionDataTask = session!.dataTaskWithURL(url!, completionHandler: nil) task.start() } 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) } ////NSURLSessionDataDelegate //完成下载,下载错误,出错了,其他方法不会执行 func URLSession(session: NSURLSession, task: NSURLSessionTask, didCompleteWithError error: NSError?) { println("didCompleteWithError") session.finishTasksAndInvalidate() dispatch_async( dispatch_get_main_queue()) { () -> Void in var message = "完成下载数据" if error != nil{ message = "下载内容失败" } self.displayAlertWithTitle("完成", message: message) NSLog(self.mutableData.description) } } //didReceiveData 和 didReceiveResponse ,两个只能存在一个,didReceiveResponse高于didReceiveData,前者有的话,后者就不能执行 //数据接收 func URLSession(session: NSURLSession, dataTask: NSURLSessionDataTask, didReceiveData data: NSData) { println("didReceiveData") data.enumerateByteRangesUsingBlock { (point:UnsafePointer<Void>, range:NSRange, stop:UnsafeMutablePointer<ObjCBool>) -> Void in let newData = NSData(bytes: point, length: range.length) self.mutableData.appendData(newData) } } // func URLSession(session: NSURLSession, dataTask: NSURLSessionDataTask, didReceiveResponse response: NSURLResponse, completionHandler: (NSURLSessionResponseDisposition) -> Void) { // // println("didReceiveResponse,\(response),\n \(dataTask)") // // } }
接着我们来看看后台委托处理的方式.这里我们加入了NSURLSessionDelegate,NSURLSessionDownloadDelegate,NSURLSessionTaskDelegate
这几个委托协议.然后类中我们声明了一个识别签名,这个签名存储在NSUserDefaults中,因为创建后台请求需要一个识别签名,来管理.其实请求处理方式跟上面差不多,知识执行的委托方法不一样,代码中我已经写上了相关的输出说明,大家调试一下就明白了
import UIKit class ViewController3:UIViewController,NSURLSessionDelegate,NSURLSessionDownloadDelegate,NSURLSessionTaskDelegate { var session:NSURLSession! var configidentifier:String{ let userDefaults:NSUserDefaults = NSUserDefaults.standardUserDefaults() let key = "configidenti" let preval = userDefaults.stringForKey(key) if let thepreval = preval { return preval! }else{ let newval = NSDate().description userDefaults.setObject(newval, forKey: key) userDefaults.synchronize() return newval } } override init() { super.init() let config = NSURLSessionConfiguration.backgroundSessionConfigurationWithIdentifier(self.configidentifier) config.timeoutIntervalForRequest = 15 session = NSURLSession(configuration: config, delegate: self, delegateQueue: nil) } required init(coder aDecoder: NSCoder) { super.init(coder: aDecoder) } override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?) { super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil) } // override func viewDidAppear(animated: Bool) { super.viewDidAppear(animated) let url = NSURL(string: "http://www.wutongwei.com") let task = session.downloadTaskWithURL(url!) task.start() } func URLSession(session: NSURLSession, downloadTask: NSURLSessionDownloadTask, didWriteData bytesWritten: Int64, totalBytesWritten: Int64, totalBytesExpectedToWrite: Int64) { NSLog("接收数据") } func URLSession(session: NSURLSession, downloadTask: NSURLSessionDownloadTask, didFinishDownloadingToURL location: NSURL) { NSLog("下载完成") } func URLSession(session: NSURLSession, task: NSURLSessionTask, didCompleteWithError error: NSError?) { NSLog("任务完成") session.finishTasksAndInvalidate() } // 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) } }
最后我们来看一下怎么上传数据.相关的基本配置跟上面的类似,不同的是,这里需要创建NSMutableURLRequest请求对象,然后调用session的uploadTaskWithRequest进行上传请求,其实也不是那么难!
import UIKit 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) } override init() { super.init() let config = NSURLSessionConfiguration.defaultSessionConfiguration() config.timeoutIntervalForRequest = 15 session = NSURLSession(configuration: config, delegate: self, delegateQueue: nil) } required init(coder aDecoder: NSCoder) { super.init(coder: aDecoder) } override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?) { super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil) } override func viewDidAppear(animated: Bool) { super.viewDidAppear(animated) let datatoup = "Hello World".dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false) let url = NSURL(string: "http://www.baidu.com") 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) }) } }
这里说明一下这个task方法,我这里扩展了NSURLSessionTask,因为使用resume来执行任务有点怪怪的,可能还没习惯.
extension NSURLSessionTask{ func start(){ self.resume() } }