preface

SessionManager manages the creation of Request and SessionDelegate, and binds Request through task. Request management Request parameter configuration code, create a task and TaskDelegate method, then SessionDelegate through the task will be distributed to TaskDelegate task, TaskDelegate agent specific content of the mission. The following is not perfect for the place to do a throw throw supplement 🧠.

Adapter – Adapter

Let’s go back to the sessionManager. swift request method from the previous article:

See πŸ‘€, where an adapter is passed in when creating a task. What is the adapter for? πŸ€”

adapt
adapt
adapt
URLRequest
request
URLRequest

If the adapt method passes in an urlRequest and returns an urlRequest, you can override the adapt method as follows:

class ZHAdapter: RequestAdapter{
    func adapt(_ urlRequest: URLRequest) throws -> URLRequest {
        var request = urlRequest
        request.setValue("XZXQWYEHNSDXXSCJHSJDSDSJD=".forHTTPHeaderField: "Token")
        request.setValue("iPhone".forHTTPHeaderField: "DeviceModel")
        return request
    }
}
Copy the code

Write an example 🌰 to try:

let urlStr = "https://www.douban.com/j/app/radio/channels"
let url = URL.init(string: urlStr)!
Alamofire.SessionManager.default.adapter = ZHAdapter()
Alamofire.request(url,method: .post,parameters: ["Username":"Henry"."Age":"18"]).responseJSON {
    (response) in
    switch response.result{
    case .success(let json):
        print("json:\(json)")
        break
    case .failure(let error):
        print("error:\(error)")
        break}}Copy the code

OKπŸ™†β™‚οΈ, done.

There is another use for the RequestAdapter protocol: redirect, which returns a new address.

class ZHAdapter: RequestAdapter{
    func adapt(_ urlRequest: URLRequest) throws -> URLRequest {
        let newURLRequest = URLRequest.init(url: URL.init(string: "https://www.douban.com/j/app/radio/channels")!return newURLRequest
    }
}
Copy the code

Conclusion πŸ—£ πŸ—£ πŸ—£ :

First of all achieveRequestAdapterOf the agreementadaptMethod and on the incomingurlRequestProcessing, such as configurationtokenIsoparameter, or yesurlRequestRedirect and get a new onerequestRequest. But the most important is must configuration: Alamofire. Our SessionManager. Default. Adapter = ZHAdapter ()

Validate – Custom validation

When making network requests, the server will generally return different status codes, and then get the status codes to carry out corresponding tasks. For example, if a certain result 404 needs to be defined as an error request, it should be processed in error. In this case, we can use validate to re-verify and define the request result.

let urlStr = "https://www.douban.com/j/app/radio/channels"
let url = URL.init(string: urlStr)!
Alamofire.request(url,method: .post,parameters: ["Username":"Henry"."Age":"18"]).responseJSON {
    (response) in
    switch response.result{
    case .success(let json):
        print("json:\(json)")
        break
    case .failure(let error):
        print("error:\(error)")
        break
    }
}.validate{ (request, response, data) -> Request.ValidationResult in
    print(response)
    guard let _ = data else {
        return .failure(NSError(domain: "You always say it's my fault.", code: 10000, userInfo: nil))
    }
    let code =  response.statusCode 
    if (code == 404 ){
        return .failure(NSError(domain: "No, no, no. Say it's my fault.", code: 10010, userInfo: nil))
    }
    return .success
}
Copy the code

Ok πŸ™†β™‚οΈ, here we are again using the chained method to call the validate method, then customizing the validation inside the closure, and then customizing the processing for the different status codes.

Retrier – re-requests

UrlSession (_ session: urlSession, task: task) is called when the SessionDelegate completes the request but the request fails. URLSessionTask, didCompleteWithError error: Error?) Method, so let’s see what does retrier do in this method

if let retrier = retrier, let error = error {
   retrier.should(sessionManager, retry: request, with: error) { [weak self] shouldRetry, timeDelay in
       guard shouldRetry else { completeTask(session, task, error) ; return }

       DispatchQueue.utility.after(timeDelay) { [weak self] in
           guard let strongSelf = self else { return }

           letretrySucceeded = strongSelf.sessionManager? .retry(request) ??false

           if retrySucceeded, let task = request.task {
               strongSelf[task] = request
               return
           } else {
               completeTask(session, task, error)
           }
       }
   }
}
Copy the code

This will determine if there is a retrier first, call the should method if there is, and call the complete callback if there is not. The source code shows that retrier is a class object that inherits from the RequestEr protocol (like RequestAdapter) and also needs to be implemented on its own:

extension ZHRetrier: RequestRetrier{
   func should(_ manager: SessionManager, retry request: Request, with error: Error, completion: @escaping RequestRetryCompletion) {
       completion(trueCompletion (1) // There is no need for it to keep repeating requests, there is a completion method required.false, 0)}}Copy the code

βš” completion. There are two parameters in completion: shouldRetry is the request or not, timeDelay is the delay time of the request. So in the code above, there is the method completion(false,0) that completes the request again.

let urlStr = "https://www.douban.com/j/app/radio/channels"
let url = URL.init(string: urlStr)!
Alamofire.SessionManager.default.retrier = ZHRetrier()
Alamofire.request(url,method: .post,parameters: ["Username":"Henry"."Age":"18"]).responseJSON {
   (response) in
   switch response.result{
   case .success(let json):
       print("json:\(json)")
       break
   case .failure(let error):
       print("error:\(error)")
       break
   }
}.validate{ (request, response, data) -> Request.ValidationResult in
   print(response)
   guard let _ = data else {
       return .failure(NSError(domain: "You always say it's my fault.", code: 10000, userInfo: nil))
   }
   let code =  response.statusCode 
   if (code == 404 ){
       return .failure(NSError(domain: "No, no, no. Say it's my fault.", code: 10010, userInfo: nil))
   }
   return .success
}
Copy the code

As one of the most important is: Alamofire. Our SessionManager. Default. Retrier = ZHRetrier ();

Timeline – the Timeline

Let’s go back to the picture at the beginning of the article, If startRequestsImmediately {request.resume()} task.resume() πŸ™…β™€οΈ if startRequestsImmediately {request.resume()} task.resume() πŸ™…β™€οΈ The task.resume() method must be stored inside the request.resume() method here. Take a look inside:

resume()
else
delegate.queue.isSuspended = false ;

Queue is an OperationQueue and is initialized in the TaskDelegate init method.

queue
TaskDelegate
request
TaskDelegate

func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) {
        if let taskDidCompleteWithError = taskDidCompleteWithError {
            taskDidCompleteWithError(session, task, error)
        } else{// omit some code queue.issuspended =false}}Copy the code

In this case, the queue is unsuspended, which means that tasks added to the queue are done after the request completes.

OKπŸ™†, let’s take a look at the implementation of Timeline with this queue:

1. StartTime – Time when a network request is initiated

resume
startTime

2. EndTime – network request endTime

DataRequest
init
queue
endTime

However, since the current queue is suspended by default, no tasks will be executed. Queue queue. IsSuspended = false is resumed when the network request completes the callback to the didCompleteWithError method, followed by endTime assignment.

InitialResponseTime – Initializes the response time

initialResponseTime

4. Set the TimeLine

ResponseSerialization.swift
Response
queue
self.timeline

self.timeline
Timeline
serializationCompletedTime
Timeline
serializationCompletedTime

5. Initialize the recording time and calculate the total time -totalDuration

TimeLine
ResponseSerialization
response
TimeLine

To borrow a summary from Bo_Bo πŸ˜€πŸ˜ΊπŸ˜ :

conclusion

The Adapter(Adapter),validate(custom validation),retrier(re-request),Timeline(Timeline) content is learned here, personal feelings are still important, for users to provide a certain convenience for encapsulation use.