๐Ÿ˜Š๐Ÿ˜Š๐Ÿ˜ŠAlamofire thematic directory. Welcome timely feedback and exchange

  • Alamofire (1) – URLSession prerequisite skill
  • Alamofire (2) — Background download
  • Alamofire (3) — Request
  • Alamofire (4) — Details you need to know
  • Alamofire (5) — Response
  • Alamofire (6) — Multiple form uploads
  • Alamofire (7) — Safety certification
  • Alamofire (8) — Final Chapter (Network Monitoring & Notifications & Downloader Packaging)

Alamofire Directory through train — Harmonious learning, not impatient!


This article mainly explains the background download, background download for the application, is a very important and relatively easy to use function. While it is true that background downloads can greatly improve the user experience, there are also a lot of pitfalls and confusion. The discussion will be carried out through URLSession and Alamofire respectively, so that the design thinking of Alamofire can be better understood by comparing learning. Alamofire continues to be updated, hope you hope!

URLSession handles background downloads

URLSession is relatively simple in terms of background processing.

// 1: initializes a background mode configuration
let configuration = URLSessionConfiguration.background(withIdentifier: self.createID())
// 2: Initializes the network download session through configuration
let session = URLSession.init(configuration: configuration, delegate: self, delegateQueue: OperationQueue.main)
// 3: session creates a downloadTask. - Resume Starts
session.downloadTask(with: url).resume()
Copy the code
  • Initialize onebackgroundThe pattern ofconfiguration.configurationThere areThree models, onlybackgroundMode to carry out background download.
  • Initialize the network download session using configurationsession, set up the related proxy, and call back the data signal response.
  • sessioncreateDownloadTask taskresumeStart (Default:suspend)
  • Then rely on the Apple-wrapped network processing, initiating the connection, sending the relevant request, and calling back the proxy response
//MARK: -session proxy
extension ViewController:URLSessionDownloadDelegate{
    func urlSession(_ session: URLSession.downloadTask: URLSessionDownloadTask.didFinishDownloadingTo location: URL) {
        // Download complete - Start sandbox migration
        print("Download complete -\(location)")
        let locationPath = location.path
        // Copy to user directory (filename named after timestamp)
        let documnets = NSHomeDirectory(a)+ "/Documents/" + self.lgCurrentDataTurnString() + ".mp4"
        print("Mobile address:\(documnets)")
        // Create file manager
        let fileManager = FileManager.default
        try! fileManager.moveItem(atPath: locationPath, toPath: documnets)
    }
    
    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
  • To achieve theURLSessionDownloadDelegatethedidFinishDownloadingToAgent, download complete transfer of temporary file data to the corresponding sandbox save
  • throughurlSession(_ session: downloadTask:didWriteData bytesWritten: totalBytesWritten: totalBytesExpectedToWrite: )The agent listens for download progress
  • This is also becauseHTTP fragment transmissionLead to the progress of a section of the feeling, in fact, to prove that the internal proxy method is constantly called, in order to progress callback!

The download function is implemented here, but there is still some way to go for the background download we need

Applications using an NSURLSession with a background configuration may be launched or resumed in the background in order to handle the completion of tasks in that session, or to handle authentication. This method will be called with the identifier of the session needing attention. Once a session has been created from a configuration object with that identifier, the session’s delegate will begin receiving callbacks. If such a session has already been created (if the app is being resumed, for instance), then the delegate will start receiving callbacks without any action by the application. You should call the completionHandler as soon as you’re finished handling the callbacks.

The Apple dad will always be able to give you good advice at the right time, and the ability to read documents will determine whether you stand on your toes in this era

class AppDelegate: UIResponder.UIApplicationDelegate {
    var window: UIWindow?
    // Used to save the completionHandler for the background download
    var backgroundSessionCompletionHandler: (() -> Void)?
    func application(_ application: UIApplication.handleEventsForBackgroundURLSession identifier: String.completionHandler: @escaping() - >Void) {
        self.backgroundSessionCompletionHandler = completionHandler
    }
}
Copy the code
  • implementationhandleEventsForBackgroundURLSessionCan perfect background download
  • Tell the agent andURLSessionRelated events are waiting to be processed.
  • Application in all withURLSession objectThis method is called after the associated background transfer completes, whether the transfer completes successfully or causes an error. The application also calls this method if one or more transports require authentication.
  • Use this method to reconnect anyURLSessionAnd update the application’s user interface. For example, you can use this method to update progress indicators or merge new content into a view. After processing the event, incompletionHandlerParameter to executeblockSo that the application can get a refresh of the user interface.
  • We’re throughhandleEventsForBackgroundURLSessionSave the corresponding callback, this is also very necessary! Tell the system background download back to refresh the screen in time

inurlSessionDidFinishEventsThe proxy implementation is called

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
  • getUIApplication.shared.delegateThe callback function executes
  • Note that the thread switches the main thread, after all, to refresh the interface

So what happens if you don’t implement the callback function in the proxy

  • The ability to download in the background is not affected
  • However, it will be very difficult to refresh the interface and affect the user experience
  • At the same time, a warning will pop up at the printer’s desk
Warning: Application delegate received call to -
application:handleEventsForBackgroundURLSession:completionHandler: 
but the completion handler was never called.
Copy the code

Second, Alamofire background download

The Alamofire framework has a nice feel to it. This rhythm is also a functional callback and supports chained requests and responses! The transaction logic is very clear, and the code readability is very concise

LGBackgroundManger.shared.manager
    .download(self.urlDownloadStr) { (url, response) -> (destinationURL: URL, options: DownloadRequest.DownloadOptions) in
    let documentUrl = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first
    let fileUrl     = documentUrl?.appendingPathComponent(response.suggestedFilename!)
    return (fileUrl!,[.removePreviousFile,.createIntermediateDirectories])
    }
    .response { (downloadResponse) in
        print("Download callback information:\(downloadResponse)")
    }
    .downloadProgress { (progress) in
        print("Download progress:\(progress)")}Copy the code
  • This encapsulates a singletonLGBackgroundMangerBackground download management class, callmangerIs also very direct.
  • Encapsulated thoughts no longer have to deal with disgusting agency events
struct LGBackgroundManger {    
    static let shared = LGBackgroundManger(a)let manager: SessionManager = {
        let configuration = URLSessionConfiguration.background(withIdentifier: "com.lgcooci.AlamofireTest.demo")
        configuration.httpAdditionalHeaders = SessionManager.defaultHTTPHeaders
        configuration.timeoutIntervalForRequest = 10
        configuration.timeoutIntervalForResource = 10
        configuration.sharedContainerIdentifier = "group.com.lgcooci.AlamofireTest"
        return SessionManager(configuration: configuration)
    }()
}
Copy the code

Maybe a lot of students are questioning why we should make it simple profit, URLSession is not very good?

  • If you areSessionManager.defalutObviously not! After all, it requires a background download, so our sessionsessionThe configuration of theURLSessionConfigurationIs the requirement thatbackgroundPatterns of
  • If you are not configured out of simple interest, or not held! When entering the background, it will be released, and the network will report an error:Error Domain=NSURLErrorDomain Code=-999 "cancelled"
  • The application layer can also be separated from the network layer.
  • Can help inAppDelegateThe callback is easy to receive directly
func application(_ application: UIApplication.handleEventsForBackgroundURLSession identifier: String.completionHandler: @escaping() - >Void) {
    LGBackgroundManger.shared.manager.backgroundCompletionHandler = completionHandler
}
Copy the code

3. SessionManger process analysis

A good blog post, after all, has to explain the process behind such a clear code

1. SessionManger initialization
public init(
    configuration: URLSessionConfiguration = URLSessionConfiguration.default,
    delegate: SessionDelegate = SessionDelegate(),
    serverTrustPolicyManager: ServerTrustPolicyManager? = nil)
{
    self.delegate = delegate
    self.session = URLSession(configuration: configuration, delegate: delegate, delegateQueue: nil)

    commonInit(serverTrustPolicyManager: serverTrustPolicyManager)
}
Copy the code
  • Initialize thesession, includingconfiguration ๆ˜ฏ defaultMode, set up some basicSessionManager.defaultHTTPHeadersRequest header information
  • Proxy handover through creationSessionDelegateThis is implemented by a class that specializes in handling agentsURLSessionThe agent of
2. The agent completes the callback

SessionDelegate is a very important class that collects all agents

  • URLSessionDelegate
  • URLSessionTaskDelegate
  • URLSessionDataDelegate
  • URLSessionDownloadDelegate
  • URLSessionStreamDelegate

We according to demand to urlSessionDidFinishEvents agent here

open func urlSessionDidFinishEvents(forBackgroundURLSession session: URLSession) {
    sessionDidFinishEventsForBackgroundURLSession?(session)
}
Copy the code
  • This is executedsessionDidFinishEventsForBackgroundURLSessionClosure execution, so when is the closure declared?
  • And if you’re smart enough, you should be able to figure this out,SessionDelegateJust a specialized class that handles agents, but not logical data,According to the conventional ideas of packaging design will be delivered to the manager class.

In our SessionManger initialization, there is a way commonInit we see sessionDidFinishEventsForBackgroundURLSession below

delegate.sessionDidFinishEventsForBackgroundURLSession ={[weak self] session in
    guard let strongSelf = self else { return }
    DispatchQueue.main.async { strongSelf.backgroundCompletionHandler?()}}Copy the code
  • This is the proxy right heredelegate.sessionDidFinishEventsForBackgroundURLSessionClosure declaration
  • As soon as the background download is complete it will come inside the closure
  • The main thread is called backbackgroundCompletionHandler, it is also aSessionMangerExternal functions provided! You’re smart enough to know that I’m hereapplication The essence of the operation!
3. Process summary
  • First of all inAppDelegatethehandleEventsForBackgroundURLSessionMethod, passing the callback closureSessionManager ็š„ backgroundCompletionHandler
  • When the download is complete and comes backSessionDelegate ็š„ urlSessionDidFinishEvents Invocation of proxy ->sessionDidFinishEventsForBackgroundURLSessioncall
  • thensessionDidFinishEventsForBackgroundURLSessionPerform – >SessionManager ็š„ backgroundCompletionHandlerThe implementation of the
  • Finally lead toAppDelegate ็š„ completionHandlerThe call

Whether you use URLSession or Alamofire for background download, the principle is the same, but Alamofire is more dependent on sinking, network layer sinking, simpler to use, which is why we need third-party frameworks in many cases. You may have felt comfortable with Alamofire in this post, so if you like it, please pay attention. I will keep updating a series of Alamofire topics, thank you!

Just ask who else is there right now? 45 degrees up in the sky, damn it! My charm with no place to put it!