Alamofire learning (I) Network foundation

Alamofire (2) URLSession

Alamofire (3) Background download principle

@TOC

  • Recently, I am learning Alamofire framework. My last blog: Alamofire Learning (I) Basic network explains some knowledge related to network protocol. This blog mainly explains the IOS API URLSession used by Alamofire framework.
  • Why learn URLSession first

URLSession is used for encapsulation in Alamofire, so it is necessary to have a deep understanding of URLSession. URLSession is equivalent to NSURLSession, but the former is the name in Swift and the latter is the name in OC, and they can be directly converted to each other. NSURLSession was launched with iOS7, mainly reconstructing and optimizing NSURLConnection, and NSURLConnection has been abandoned in iOS 9, so NSURLSession is the replacement of NSURLConnection.

URLSession profile

Alamofire is a Swift based network library for iOS and macOS. It provides a more elegant interface on Top of Apple’s basic network architecture to simplify the onerous and frequently used tasks of network requests. Alamofire provides chained request/ Response methods, JSON parameter and response serialization, authentication, and other features. The elegance of Alamofire is that it is written entirely by Swift and inherits no features from its Objective-C version, AFNetworking.

Since our Alamofire is a network framework encapsulated to Apple’S URLSession, we need to be familiar with IOS system API URLSession before exploring Alamofire in addition to mastering some necessary network related knowledge.

Let’s start with an overview:

URLSession class member property

1. URLSessionConfiguration

  • Three session modes
Session model The characteristics of describe
Default Session mode (Default) The working mode of NSURLConnection is similar to that of NSURLConnection. NSURLConnection uses a persistent policy based on disk cache and uses the certificate stored in the user keychain for authentication and authorization. The default mode is usually enough for us to use. In default mode, the system creates a persistent cache and stores the certificate in the user’s key string
Ephemeral Session mode This mode does not use disk to store any data. All caches, certificates, cookies, etc. associated with the session are stored in RAM, so when the program invalidates the session, the cached data is automatically emptied. The system does not have any persistent storage. The lifetime of all content is the same as that of a session. When a session is invalid, all content is automatically released.
Background Session Mode (BACKGROUND) In this mode, upload and download are completed in the background. When creating a Configuration object, an NSString ID is required to identify the background session that completes the work. Background creates a session that can transfer data in the background even when the APP is closed. Background mode is very similar to default mode, except that background mode uses a separate thread for data transfer. Background mode can run tasks if the application hangs, exits, or crashes. You can also use identifiers to restore forward. Note that the background Session must be created with a unique identifier, so that the next time the APP runs, it can be distinguished according to the identifier. If the user closes the APP,IOS closes all background sessions. In addition, after being forcibly closed by the user, IOS system will not actively wake up the APP, and data transmission will continue only after the user starts the APP next time

2. URLSessionTask

2. 1 URLSessionDataTaskData:

URLSessionDataTask: Handles getting data from the server into memory from HTTP GET requests.

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 sessions

2 2.URLSessionUploadTaskUpload:

URLSessionUploadTask: uploads a file from a hard disk to the server in HTTP POST or PUT mode

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.

2. 3 URLSessionDownloadTaskDownload:

URLSessionDownloadTask: Downloads a file from a remote server to a temporary file location

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.

2. 4 URLSessionStreamTaskFlow:

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.

3. URLSessionDelegate

4. Cache policy NSURLRequestCachePolicy

Caching strategies role instructions
NSURLRequestUseProtocolCachePolicy = 0 Default Cache Policy If an NSCachedURLResponse does not exist for the request, the data will be retrieved from the source. If the request has a cached response, the URL loading system checks the response to determine if it specifies that the content must be re-validated. If the content must be reactivated, a connection is established to the source to see if the content has changed. If the content has not changed, the response returns data from the local cache. If the content changes, the data will be retrieved from the source
NSURLRequestReloadIgnoringLocalCacheData = 1 Urls should load source-side data and do not use locally cached data
NSURLRequestReloadIgnoringLocalAndRemoteCacheData =4 Locally cached data, proxies, and other mediations ignore their caches and load source data directly
NSURLRequestReloadIgnoringCacheData = NSURLRequestReloadIgnoringLocalCacheData
NSURLRequestReturnCacheDataElseLoad = 2 Specifies that stored cached data should be used to respond to a request regardless of its lifetime or expiration. If there is no existing data in the cache to respond to the request, the data is loaded from the source
NSURLRequestReturnCacheDataDontLoad = 3 Specifies the cached data that is stored to fulfill the request regardless of lifetime or expiration. If there is no data in the cache to respond to a URL load request, no attempt is made to load data from the source segment and the load request is considered to have failed. This constant specifies a behavior similar to offline mode
NSURLRequestReloadRevalidatingCacheData = 5 Specifies that cached data is allowed to respond to a request if the stored cached data is validated by the source segment that provides it, otherwise data is loaded from the source segment.

5. URLSession properties

Attribute category The attribute name role
conventional
conventional identifier Configures the background session identifier of the object
conventional httpAdditionalHeaders Dictionary of additional header files sent with the request
conventional networkServiceType Network service type
conventional allowsCellularAccess A Boolean value that determines whether a connection should be made over a cellular network
conventional timeoutIntervalForRequest Timeout interval to use while waiting for other data
conventional timeoutIntervalForResource The maximum amount of time a resource request should allow
conventional sharedContainerIdentifier The identifier of the shared container of the file in the background URL session should be downloaded
conventional waitsForConnectivity A Boolean value indicating whether the session should wait for the connection to become available or fail immediately
Setting the Cookie Policy
httpCookieAcceptPolicy A policy constant that determines when cookies should be accepted
httpShouldSetCookies A Boolean value that determines whether the request should contain cookies from the Cookie store
httpCookieStorage A single object (shared instance) that manages cookie storage
HTTPCookie Object that represents an HTTP cookie. It is an immutable object initialized from a dictionary containing the cookie attribute
Setting a Security Policy
tlsMaximumSupportedProtocol The maximum TLS protocol version the client should request when connecting in this session
tlsMinimumSupportedProtocol Protocol Indicates the minimum TLS protocol to be accepted during the negotiation
urlCredentialStorage A credential store that provides authentication credentials
Setting the Cache Policy
urlCache The URL cache used to provide cached responses to requests in the session
requestCachePolicy A predefined constant that determines when a response is returned from the cache
Support background transfer
sessionSendsLaunchEvents A Boolean value indicating whether the application should continue or start in the background when the transfer is complete
isDiscretionary A Boolean value that determines whether background tasks can be scheduled based on the system’s judgment for optimal performance
Supports user-defined protocols
protocolClasses An array of additional protocol subclasses that process the request in the session
URLProtocol An NSURLProtocol object handles load protocol-specific URL data. The NSURLProtocol class itself is an abstract class that can handle the URL infrastructure for a specific URL scheme. You can subclass any custom protocol or URL scheme supported by your application
Supports multipathing TCP
multipathServiceType Specifies the service type of the multipath TCP connection policy used to transfer data over Wi-Fi and cellular interfaces
URLSessionConfiguration.MultipathServiceType Constant to specify the type of service used by multipath TCP
Set HTTP policy and proxy properties
httpMaximumConnectionsPerHost The maximum number of simultaneous connections to a given host
httpShouldUsePipelining A Boolean value that determines whether the session should use HTTP pipelining
connectionProxyDictionary Contains a dictionary of information about the agents used in this session
Support for connection changes
waitsForConnectivity A Boolean value indicating whether the session should wait for the connection to become available or fail immediately
Attribute category The attribute name role

URLSession use

URLSession Usage flow

URLSession upload

For more information please refer to the Official Apple documentation: Uploading Streams of Data

func postsesssionUploadTask(a){
        //1. Create session objects
        let config:URLSessionConfiguration=URLSessionConfiguration.default
        let session:URLSession=URLSession.init(configuration: config, delegate: self, delegateQueue: OperationQueue.main)
        //2. Create a task based on the session object
         let urlstr="\(BASEURL)"+LUNBOURL
        let urls: NSURL = NSURL(string: urlstr)!
        //3. Create mutable request objects
        var request:URLRequest  = URLRequest(url: urls as URL)
        //4. Change the request method to POST
        request.httpMethod = "POST"
        //5. Set the request body -----
        request.httpBody = "".data(using: String.Encoding.utf8)
        //6. Create a Task based on the session object.
        / * the first parameter: the request object The second parameter: the completionHandler callback (requests to complete the data: success | failure 】 【 response body information (data) expectations response: the response headers, mainly on the server side to describe the error: Error message, if the request fails, error has the value upDta: binary data to be uploaded */
let images:UIImage=UIImage.init(named: "bannerhomeOne")!
        let upData:Data=UIImagePNGRepresentation(images)!
// Upload data through data
        let upTask=session.uploadTask(with: request, from: upData) { (data, res, error) in
            // After uploading
            iferror ! =nil{
                print(error)
            }else{
                let str = String(data: data! , encoding:String.Encoding.utf8)
                print("Upload completed:\(str)")
            }
        }
       upTask.resume()
}    

Copy the code

URLSession download

Ordinary download

  • (1) Start a download task first
let configuration = URLSessionConfiguration.background(withIdentifier: self.createID())

        let session = URLSession.init(configuration: configuration, delegate: self, delegateQueue: OperationQueue.main)
        
        session.downloadTask(with: url).resume()
Copy the code
  • (2) Set up the proxy, accept the callback, save the file
/ / after the download is complete callback URLSessionDownloadDelegate agent
func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didFinishDownloadingTo location: URL) {
        print("Download complete -\(location)")}func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didWriteData bytesWritten: Int64, totalBytesWritten: Int64, totalBytesExpectedToWrite: Int64) {
        print(" bytesWritten \(bytesWritten)\n totalBytesWritten \(totalBytesWritten)\n totalBytesExpectedToWrite \(totalBytesExpectedToWrite)")
        print("Download progress:\(Double(totalBytesWritten)/Double(totalBytesExpectedToWrite))\n")}Copy the code

The background to download

In addition to the steps (1,2) required for common downloads, background downloads need to perform the following operations

  • (3) Enable background download permission
 // Used to save the completionHandler for the background download
  var backgroundSessionCompletionHandler: (() -> Void)?
  
  func application(_ application: UIApplication, handleEventsForBackgroundURLSession identifier: String, completionHandler: @escaping (a) -> Void) {
      self.backgroundSessionCompletionHandler = completionHandler
  }
Copy the code
  • (4) When the download is complete, call the system callback to update the screen
func urlSessionDidFinishEvents(forBackgroundURLSession session: URLSession) {
      print("Background task download back")
      DispatchQueue.main.async {
          guard let appDelegate = UIApplication.shared.delegate as? AppDelegate.let backgroundHandle = appDelegate.backgroundSessionCompletionHandler else { return }
          backgroundHandle()
      }
  }
Copy the code

Resumable download

  1. Defined variables, and follow NSURLSessionDownloadDelegate agreement
    var downloadTask : NSURLSessionDownloadTask?
    var partialData : NSData?
    var session : NSURLSession?
    var request : NSMutableURLRequest?
Copy the code
  1. Add click events for each button
    // Start downloading
    @IBAction func onDownLoad(sender: AnyObject) {
        self.downloadFile()
    }
    // Suspend the download
    @IBAction func onSuspend(sender: AnyObject) {
        if(self.downloadTask ! =nil)
        {
            // Suspend the download task and save the downloaded data
            self.downloadTask? .cancelByProducingResumeData({ (resumeData:NSData!). ->Void in
                self.partialData = resumeData
                self.downloadTask = nil})}// downloadTask! .suspend()
    }
    // Resume the download
    @IBAction func onResume(sender: AnyObject) {
        if(self.downloadTask == nil)
        {
            // Determine whether the data has been downloaded again. If so, resume the download. If not, completely download again
        if(self.partialData ! =nil)
        {
            self.downloadTask = self.session? .downloadTaskWithResumeData(self.partialData!)
            }
        else{
            self.downloadTask = self.session? .downloadTaskWithRequest(self.request!) } } downloadTask! .resume() }// Start downloading files
    func downloadFile(a)
    {
        NSLog("Downloading")
        / / create a URL
        var urlStr:NSString = NSString(string: "http://cdn.wall88.com/51a317b5ef36713194.jpg")
        urlStr = urlStr.stringByAddingPercentEscapesUsingEncoding(NSUTF8StringEncoding)!
        var url = NSURL(string: urlStr)!
        // Create the request
        request = NSMutableURLRequest(URL: url)
        // Create a default session
        var sessionConfig : NSURLSessionConfiguration = NSURLSessionConfiguration.defaultSessionConfiguration()
        sessionConfig.timeoutIntervalForRequest = 20 // Set the request timeout period
        sessionConfig.allowsCellularAccess = true // Whether cellular downloading is allowed
        // Create a session
        session = NSURLSession(configuration: sessionConfig, delegate: self, delegateQueue: nil)// Specify the configuration and proxydownloadTask = session! .downloadTaskWithRequest(request!) downloadTask! .resume() }Copy the code
  1. Update the progress bar based on the size of the downloaded content
    // Set the page state
    func setUIStatus(totalBytesWritten : Int64,expectedToWrite totalBytesExpectedToWrite:Int64 )
    {
        // Call main thread to refresh UI
        dispatch_async(dispatch_get_main_queue(), {
            if(Int(totalBytesExpectedToWrite) ! =0 && Int(totalBytesWritten) ! =0)
            {
                // Update the progress bar
                self.ps.progress = Float(Float(totalBytesWritten) / Float(totalBytesExpectedToWrite))
                if(totalBytesExpectedToWrite == totalBytesWritten)
                {
                    self.lbl_hint.text! = "Download complete"
                    UIApplication.sharedApplication().networkActivityIndicatorVisible = false
                    self.btn_download.enabled = true
                }
                else{
                    self.lbl_hint.text = "Downloading"
                    UIApplication.sharedApplication().networkActivityIndicatorVisible = true}}})}Copy the code
  1. The download file
    // The task is complete, regardless of whether the download succeeded
    func URLSession(session: NSURLSession, task: NSURLSessionTask, didCompleteWithError error: NSError?) {
        self.setUIStatus(0, expectedToWrite: 0)
        if(error ! =nil)
        {
            NSLog("error is:\(error! .localizedDescription)")}}// Download complete
    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()
        // Check whether the file exists and delete it
        if(defalutManager.fileExistsAtPath(savePath))
        {
            defalutManager.removeItemAtPath(savePath, error: &error)
        }
        // After successful download, the file is saved in a temporary directory. You need to copy the file to the directory
        defalutManager.copyItemAtURL(location, toURL: saveUrl, error: &error)
        if(error ! =nil)
        {
        NSLog("\(error)")}}/ / download
    func URLSession(session: NSURLSession, downloadTask: NSURLSessionDownloadTask, didWriteData bytesWritten: Int64, totalBytesWritten: Int64, totalBytesExpectedToWrite: Int64) {
        self.setUIStatus(totalBytesWritten, expectedToWrite: totalBytesExpectedToWrite)
    }
Copy the code

Refer to daishen blog: juejin.cn/post/684490…