Alamofire学习(一)网络基础swift
@TOC缓存
Alamofire中是使用URLSession进行封装的,因此有必要去先深刻了解下URLSession. URLSession等同于NSURLSession,只是前者是Swift中的名字,后者是OC中的名字,他们之间是能够直接相互转换的。NSURLSession是同iOS7一同推出的,主要是对NSURLConnection进行了重构和优化,而且NSURLConnection在iOS 9的时候也已经被废弃,因此NSURLSession是NSURLConnection的取代者。安全
Alamofire是一个为iOS和macOS打造的并基于Swift的网络库.它在Apple的基础网络架构上提供了更加优雅的接口来简化繁重而经常使用的网络请求任务。 Alamofire提供了链式的request/response方法,JSON的传参和响应序列化,身份认证和其余特性。Alamofire的优雅之处在于它完彻底全是由Swift写成的,而且没有从它的Objective-C版本-AFNetworking那继承任何特性。服务器
由于咱们的Alamofire
是对苹果URLSession
的封装的网络框架,因此在探索Alamofire
以前,咱们除了须要掌握一些必备的网络相关知识外,还须要熟悉IOS的系统API URLSession
。markdown
先来看一张概要图:cookie
会话模式 | 特色 | 描述 |
---|---|---|
默认会话模式(default) | 工做模式相似于原来的NSURLConnection,使用的是基于磁盘缓存的持久化策略,使用用户keychain中保存的证书进行认证受权。 | 默认模式,一般咱们用这种模式就足够了。default模式下系统会建立一个持久化的缓存并在用户的钥匙串中存储证书 |
瞬时会话模式(ephemeral) | 该模式不使用磁盘保存任何数据。全部和会话相关的caches,证书,cookies等都被保存在RAM中,所以当程序使会话无效,这些缓存的数据就会被自动清空。 | 系统没有任何持久性存储,全部内容的生命周期都与session相同,当session无效时,全部内容自动释放。 |
后台会话模式(background) | 该模式在后台完成上传和下载,在建立Configuration对象的时候须要提供一个NSString类型的ID用于标识完成工做的后台会话。 | background建立一个能够在后台甚至APP已经关闭的时候仍然在传输数据的会话。background模式与default模式很是类似,不过background模式会用一个独立线程来进行数据传输。background模式能够在程序挂起,退出,崩溃的状况下运行task。也能够利用标识符来恢复进。注意,后台Session必定要在建立的时候赋予一个惟一的identifier,这样在APP下次运行的时候,可以根据identifier来进行相关的区分。若是用户关闭了APP,IOS 系统会关闭全部的background Session。并且,被用户强制关闭了之后,IOS系统不会主动唤醒APP,只有用户下次启动了APP,数据传输才会继续 |
URLSessionDataTask: 处理从HTTP get请求中从服务器获取数据到内存中。网络
Use URLSession’s dataTask(with:) and related methods to create URLSessionDataTask instances. Data tasks request a resource, returning the server’s response as one or more NSData objects in memory. They are supported in default, ephemeral, and shared sessions, but are not supported in background sessionssession
URLSessionUploadTask:上传硬盘中的文件到服务器,通常是HTTP POST 或 PUT方式
Use URLSession’s uploadTask(with:from:) and related methods to create URLSessionUploadTask instances. Upload tasks are like data tasks, except that they make it easier to provide a request body so you can upload data before retrieving the server’s response. Additionally, upload tasks are supported in background sessions.
URLSessionDownloadTask: 从远程服务器下载文件到临时文件位置
Use URLSession’s downloadTask(with:) and related methods to create URLSessionDownloadTask instances. Download tasks download a resource directly to a file on disk. Download tasks are supported in any type of session.
Use URLSession’s streamTask(withHostName:port:) or streamTask(with:) to create URLSessionStreamTask instances. Stream tasks establish a TCP/IP connection from a host name and port or a net service object.
缓存策略 | 做用 | 说明 |
---|---|---|
NSURLRequestUseProtocolCachePolicy = 0 | 默认缓存策略 | 若是一个NSCachedURLResponse对于请求并不存在,数据将会从源端获取。若是请求拥有一个缓存的响应,那么URL加载系统会检查这个响应来决定,若是它指定内容必须从新生效的话。假如内容必须从新生效,将创建一个连向源端的链接来查看内容是否发生变化。假如内容没有变化,那么响应就从本地缓存返回数据。若是内容变化了,那么数据将从源端获取 |
NSURLRequestReloadIgnoringLocalCacheData = 1 | URL应该加载源端数据,不使用本地缓存数据 | |
NSURLRequestReloadIgnoringLocalAndRemoteCacheData =4 | 本地缓存数据、代理和其余中介都要忽视他们的缓存,直接加载源数据 | |
NSURLRequestReloadIgnoringCacheData | = NSURLRequestReloadIgnoringLocalCacheData | |
NSURLRequestReturnCacheDataElseLoad = 2 | 指定已存的缓存数据应该用来响应请求,无论它的生命时长和过时时间。若是在缓存中没有已存数据来响应请求的话,数据从源端加载 | |
NSURLRequestReturnCacheDataDontLoad = 3 | 指定已存的缓存数据用来知足请求,无论生命时长和过时时间。若是在缓存中没有已存数据来响应URL加载请求的话,不去尝试从源段加载数据,此时认为加载请求失败。这个常量指定了一个相似于离线模式的行为 | |
NSURLRequestReloadRevalidatingCacheData = 5 | 指定若是已存的缓存数据被提供它的源段确认为有效则容许使用缓存数据响应请求,不然从源段加载数据。 |
属性类别 | 属性名称 | 做用 |
---|---|---|
常规 | ||
常规 | identifier | 配置对象的后台会话标识符 |
常规 | httpAdditionalHeaders | 与请求一块儿发送的附加头文件的字典 |
常规 | networkServiceType | 网络服务的类型 |
常规 | allowsCellularAccess | 一个布尔值,用于肯定是否应经过蜂窝网络进行链接 |
常规 | timeoutIntervalForRequest | 等待其余数据时使用的超时间隔 |
常规 | timeoutIntervalForResource | 资源请求应该容许的最大时间量 |
常规 | sharedContainerIdentifier | 应该下载后台URL会话中的文件的共享容器的标识符 |
常规 | waitsForConnectivity | 一个布尔值,指示会话是否应等待链接变为可用或者当即失败 |
设置Cookie政策 | ||
httpCookieAcceptPolicy | 决定什么时候应该接受Cookie的策略常量 | |
httpShouldSetCookies | 一个布尔值,用于肯定请求是否应包含来自Cookie存储的Cookie | |
httpCookieStorage | 管理cookie存储的单一对象(共享实例) | |
HTTPCookie | 表示HTTP cookie的对象。它是一个不可变的对象,从包含cookie属性的字典中初始化 | |
设置安全策略 | ||
tlsMaximumSupportedProtocol | 在此会话中进行链接时客户端应请求的最大TLS协议版本 | |
tlsMinimumSupportedProtocol | 协议协商期间应该接受的最小TLS协议 | |
urlCredentialStorage | 提供身份验证凭据的凭证存储 | |
设置缓存策略 | ||
urlCache | 用于向会话中的请求提供缓存响应的URL缓存 | |
requestCachePolicy | 一个预约义常量,用于肯定什么时候从缓存中返回响应 | |
支持后台转移 | ||
sessionSendsLaunchEvents | 一个布尔值,指示在传输完成时是否应该在后台继续或启动应用程序 | |
isDiscretionary | 一个布尔值,用于肯定是否能够根据系统的判断来调度后台任务以得到最佳性能 | |
支持自定义协议 | ||
protocolClasses | 在会话中处理请求的额外协议子类的数组 | |
URLProtocol | 一个NSURLProtocol对象处理加载协议特定的URL数据。在NSURLProtocol类自己是一个抽象类,能够为与特定URL方案的URL处理基础设施。您能够为您的应用支持的任何自定义协议或URL方案建立子类 | |
支持多路径TCP | ||
multipathServiceType | 指定用于经过Wi-Fi和蜂窝接口传输数据的多路径TCP链接策略的服务类型 | |
URLSessionConfiguration.MultipathServiceType | 指定多路径TCP使用的服务类型的常量 | |
设置HTTP策略和代理属性 | ||
httpMaximumConnectionsPerHost | 同时链接到给定主机的最大数量 | |
httpShouldUsePipelining | 一个布尔值,用于肯定会话是否应使用HTTP流水线 | |
connectionProxyDictionary | 包含有关在此会话中使用的代理信息的字典 | |
支持链接变化 | ||
waitsForConnectivity | 一个布尔值,指示会话是否应等待链接变为可用或者当即失败 | |
属性类别 | 属性名称 | 做用 |
详情能够参考:苹果官方文档:Uploading Streams of Data
func postsesssionUploadTask(){ //1.建立会话对象 let config:URLSessionConfiguration=URLSessionConfiguration.default let session:URLSession=URLSession.init(configuration: config, delegate: self, delegateQueue: OperationQueue.main) //2.根据会话对象建立task let urlstr="\(BASEURL)"+LUNBOURL let urls: NSURL = NSURL(string: urlstr)! //3.建立可变的请求对象 var request:URLRequest = URLRequest(url: urls as URL) //4.修改请求方法为POST request.httpMethod = "POST" //5.设置请求体-----能够不设置,有默认的 request.httpBody = "".data(using: String.Encoding.utf8) //6.根据会话对象建立一个Task(发送请求) /* 第一个参数:请求对象 第二个参数:completionHandler回调(请求完成【成功|失败】 data:响应体信息(指望的数据) response:响应头信息,主要是对服务器端的描述 error:错误信息,若是请求失败,则error有值 upDta:要上传的二进制数据 */ let images:UIImage=UIImage.init(named: "bannerhomeOne")! let upData:Data=UIImagePNGRepresentation(images)! //经过data数据上传 let upTask=session.uploadTask(with: request, from: upData) { (data, res, error) in //上传完毕后 if error != nil{ print(error) }else{ let str = String(data: data!, encoding: String.Encoding.utf8) print("上传完毕:\(str)") } } upTask.resume() } 复制代码
let configuration = URLSessionConfiguration.background(withIdentifier: self.createID()) let session = URLSession.init(configuration: configuration, delegate: self, delegateQueue: OperationQueue.main) session.downloadTask(with: url).resume() 复制代码
//下载完成以后就回调URLSessionDownloadDelegate代理 func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didFinishDownloadingTo location: URL) { print("下载完成 - \(location)") } func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didWriteData bytesWritten: Int64, totalBytesWritten: Int64, totalBytesExpectedToWrite: Int64) { print(" bytesWritten \(bytesWritten)\n totalBytesWritten \(totalBytesWritten)\n totalBytesExpectedToWrite \(totalBytesExpectedToWrite)") print("下载进度: \(Double(totalBytesWritten)/Double(totalBytesExpectedToWrite))\n") } 复制代码
后台下载除了须要普通下载的必须步骤(1,2)外还需作以下处理
//用于保存后台下载的completionHandler var backgroundSessionCompletionHandler: (() -> Void)? func application(_ application: UIApplication, handleEventsForBackgroundURLSession identifier: String, completionHandler: @escaping () -> Void) { self.backgroundSessionCompletionHandler = completionHandler } 复制代码
func urlSessionDidFinishEvents(forBackgroundURLSession session: URLSession) { print("后台任务下载回来") DispatchQueue.main.async { guard let appDelegate = UIApplication.shared.delegate as? AppDelegate, let backgroundHandle = appDelegate.backgroundSessionCompletionHandler else { return } backgroundHandle() } } 复制代码
var downloadTask : NSURLSessionDownloadTask? var partialData : NSData? var session : NSURLSession? var request : NSMutableURLRequest? 复制代码
//开始下载 @IBAction func onDownLoad(sender: AnyObject) { self.downloadFile() } //挂起下载 @IBAction func onSuspend(sender: AnyObject) { if(self.downloadTask != nil) { //挂起下载任务,将下载好的数据进行保存 self.downloadTask?.cancelByProducingResumeData({ (resumeData:NSData!) -> Void in self.partialData = resumeData self.downloadTask = nil }) } // downloadTask!.suspend() } //恢复下载 @IBAction func onResume(sender: AnyObject) { if(self.downloadTask == nil) { //判断是否又已下载数据,有的话就断点续传,没有就彻底从新下载 if(self.partialData != nil) { self.downloadTask = self.session?.downloadTaskWithResumeData(self.partialData!) } else{ self.downloadTask = self.session?.downloadTaskWithRequest(self.request!) } } downloadTask!.resume() } //开始下载文件 func downloadFile() { NSLog("正在下载") //建立URL var urlStr:NSString = NSString(string: "http://cdn.wall88.com/51a317b5ef36713194.jpg") urlStr = urlStr.stringByAddingPercentEscapesUsingEncoding(NSUTF8StringEncoding)! var url = NSURL(string: urlStr)! //建立请求 request = NSMutableURLRequest(URL: url) //建立默认会话 var sessionConfig : NSURLSessionConfiguration = NSURLSessionConfiguration.defaultSessionConfiguration() sessionConfig.timeoutIntervalForRequest = 20 //设置请求超时时间 sessionConfig.allowsCellularAccess = true //是否容许蜂窝网络下载 //建立会话 session = NSURLSession(configuration: sessionConfig, delegate: self, delegateQueue: nil)//指定配置和代理 downloadTask = session!.downloadTaskWithRequest(request!) downloadTask!.resume() } 复制代码
//设置页面状态 func setUIStatus(totalBytesWritten : Int64,expectedToWrite totalBytesExpectedToWrite:Int64 ) { //调用主线程刷新UI dispatch_async(dispatch_get_main_queue(), { if(Int(totalBytesExpectedToWrite) != 0 && Int(totalBytesWritten) != 0) { //更新进度条 self.ps.progress = Float(Float(totalBytesWritten) / Float(totalBytesExpectedToWrite)) if(totalBytesExpectedToWrite == totalBytesWritten) { self.lbl_hint.text! = "下载完毕" UIApplication.sharedApplication().networkActivityIndicatorVisible = false self.btn_download.enabled = true } else{ self.lbl_hint.text = "正在下载" UIApplication.sharedApplication().networkActivityIndicatorVisible = true } } } ) } 复制代码
//任务完成,不论是否下载成功 func URLSession(session: NSURLSession, task: NSURLSessionTask, didCompleteWithError error: NSError?) { self.setUIStatus(0, expectedToWrite: 0) if(error != nil) { NSLog("error is:\(error!.localizedDescription)") } } //下载完成 func URLSession(session: NSURLSession, downloadTask: NSURLSessionDownloadTask, didFinishDownloadingToURL location: NSURL) { var error:NSError? var cachePath : NSString = NSSearchPathForDirectoriesInDomains(NSSearchPathDirectory.CachesDirectory, NSSearchPathDomainMask.UserDomainMask, true).first as NSString var savePath = cachePath.stringByAppendingPathComponent(lbl_title.text!) NSLog("\(savePath)") var saveUrl : NSURL = NSURL(fileURLWithPath: savePath)! var defalutManager = NSFileManager.defaultManager() //判断文件是否存在,存在则删除 if(defalutManager.fileExistsAtPath(savePath)) { defalutManager.removeItemAtPath(savePath, error: &error) } //下载成功后,文件是保存在一个临时的目录中的,须要本身拷置到该文件的目录 defalutManager.copyItemAtURL(location, toURL: saveUrl, error: &error) if(error != nil) { NSLog("\(error)") } } //下载中 func URLSession(session: NSURLSession, downloadTask: NSURLSessionDownloadTask, didWriteData bytesWritten: Int64, totalBytesWritten: Int64, totalBytesExpectedToWrite: Int64) { self.setUIStatus(totalBytesWritten, expectedToWrite: totalBytesExpectedToWrite) } 复制代码
参考大神博客:juejin.cn/post/684490…