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();//这个是临时数据下载,适用于小数据下载
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()
}
}