😊😊😊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!
SesssionManager to SessionDelegate layering was introduced in the previous Alamofire- Background Download! Let me summarize and then start a very important Alamofire module, Request!
I. Summary of SessionManager
-
SesssionManager is the externally provided manager that has all the functionality of the entire Alamofire.
request
The request,Download, upload, stream
- Request header Settings and multiple form header Settings
session
Direct external supply, convenient and free handling- Initialize exposure to facilitate free factory construction, such as
URLSessionConfiguration
Configuration mode of - Retry and adapt requests
- Closures provide externally:
backgroundCompletionHandler
The background download comes back and listens for the closure - One of the very important points is that
SesssionManager
把Session
Delegate to a specialized class:SessionDelegate
-
SessionDelegate URLSessionDelegate, URLSessionTaskDelegate, URLSessionDataDelegate, URLSessionDownloadDelegate, Agent URLSessionStreamDelegate etc.
-
More interesting: SessionDelegate also provides external closures, meaning that all internal implementations of the delegate can be listened to externally. Of course, all external closures fall into two categories:
- Add closure execution inside the original proxy callback.
- Alternatively, if the proxy comes back, the lower proxy delivery is not performed and the external closure callback is performed
Conclusion:
SesssionManager
Responsible for creation and managementRequest
Objects and their underlying layersNSURLSession
First of all, I will post a very familiar picture to you. Understanding this picture will be very helpful for the following understanding of Request
- As you can see from the picture above, our external module is
SesssionManager
It provides a lot of functionality to outside users - But the real implementers of this work are made up of
IOS, Android, front-end, back-end, testing
Implementation of! - Which one
iOS
For module tasks, there areHomepage, Discovery, My, SDK, video....
Modules need to be implemented, but our project manager may not even know what they are and how to implement them! All of them if all of themSesssionManager
To implement, obviously coupling is too strong, and the task is messy, does not reflect the effect of a great project layered architecture. So in theiOS
Task refinement andSesssionManager
In between, there is a small manager, right: he knows the details and scheduling. Yes: He canSesssionManager
Coordinate and cooperate. That isRequest
Second, the Request
1. Request parameter encoding
-
First of all, I would like to explain that Alamofire supports coding formats. The specific format differences are easy to understand according to the name. If you really can’t understand, you can search and fill the gaps by yourself
- URLEncoding
- JSONEncoding
- PropertyListEncoding
-
let encodedURLRequest = try encoding.encode(originalRequest! , with: parameters) also encode the request through this code
public func encode(_ urlRequest: URLRequestConvertible, with parameters: Parameters?) throws -> URLRequest {
var urlRequest = try urlRequest.asURLRequest()
guard let parameters = parameters else { return urlRequest }
if let method = HTTPMethod(rawValue: urlRequest.httpMethod ?? "GET"), encodesParametersInURL(with: method) {
guard let url = urlRequest.url else {
throw AFError.parameterEncodingFailed(reason: .missingURL)
}
if var urlComponents = URLComponents(url: url, resolvingAgainstBaseURL: false), !parameters.isEmpty {
let percentEncodedQuery = (urlComponents.percentEncodedQuery.map{$0 + "&"}????"") + query(parameters)
urlComponents.percentEncodedQuery = percentEncodedQuery
urlRequest.url = urlComponents.url
}
} else {
if urlRequest.value(forHTTPHeaderField: "Content-Type") = =nil {
urlRequest.setValue("application/x-www-form-urlencoded; charset=utf-8", forHTTPHeaderField: "Content-Type")
}
urlRequest.httpBody = query(parameters).data(using: .utf8, allowLossyConversion: false)}return urlRequest
}
Copy the code
-
Code to consult, here is a summary
-
First take out the request method, according to different request method, parameter encoding is different
.get, .head, .delete
The three methods are to concatenate the parameters directly toURL
behind- Other requests through the request body (
httpBody
)
-
Since our request is ASCII encoded, the first step to percentage-coding is to percentage-code all routes for the current request
-
Parameter convenient coding, splicing out
private func query(_ parameters: [String: Any]) -> String {
var components: [(String.String)] = []
for key in parameters.keys.sorted(by: <) {
let value = parameters[key]!
components += queryComponents(fromKey: key, value: value)
}
return components.map { "\ [$0)=\ [$1)" }.joined(separator: "&")}Copy the code
- through
ASCII
You sort it from small to large queryComponents
This method code is overly omitted.- I’m going to take recursive parameters,
- the
The key and the value
Take it out, and then do a percent code. - Put into the tuple to save, forming a pair of parameters
- Let’s add a tuple to an array
- The map mapping
($0) = \ ($1)
- Type a separator between the elements
&
Normal methods simply concatenate the URL, such as the POST method, which puts these encoded pairs into the request body. And you have to addContent-Type
The request header
2. Request internal relationship review
After exploring the parameter encoding of one of the request’s tedious tasks, start analyzing the process inside: URL -> Request -> Task. This process also establishes the binding relationship between task and request
open func request(_ urlRequest: URLRequestConvertible) -> DataRequest {
var originalRequest: URLRequest?
do {
originalRequest = try urlRequest.asURLRequest()
let originalTask = DataRequest.Requestable(urlRequest: originalRequest!)
let task = try originalTask.task(session: session, adapter: adapter, queue: queue)
let request = DataRequest(session: session, requestTask: .data(originalTask, task))
delegate[task] = request
if startRequestsImmediately { request.resume() }
return request
} catch {
return request(originalRequest, failedWith: error)
}
}
Copy the code
- Internal create
Requestable
To help those belowDataRequest
createTask
“, also a common saying, tasks are layered, and the architecture is clearer - The binding
The task and the request
Will it be convenient for theSessionDelegate
Deliver the task,task
Direct retrieval,request
Convenient direct access - Direct task
request.resume()
Start the
Request
The initialization takes advantage of the convenience of enumerations, constructs are created, and related information is saved
May be a lot of partners at this time will have doubts, you are not throughSessionDelegate
Implementation proxy, why have one hereDataTaskDelegate
-
The first thing to understand is that the SessionDelegate is the delegate follower for all sessions, and any proxy will come and respond.
-
The DataTaskDelegate is the implementor of our specific tedious task, and all of the methods in the DataTaskDelegate are responded to by the SessionDelegate.
-
To put it bluntly, it is the relationship between the whole and the part
-
SessionDelegate is the general responder to events, but specific transactions should be assigned to specific people to execute. You can’t have all the code listed here just because the SessionDelegate gets all the responses. Obviously that would lead to confusion. Respond to the general agent and then give professional people to do professional things according to different needs. The coupling is greatly reduced and the architecture is more layered.
-
There is also an important point about asynchrony: delegate[task] = request to give our SessionDelegate a handy ability to get in time
open func urlSession(
_ session: URLSession,
downloadTask: URLSessionDownloadTask,
didFinishDownloadingTo location: URL)
{
// Omit attribute closure callback
if let delegate = self[downloadTask]? .delegateas? DownloadTaskDelegate {
delegate.urlSession(session, downloadTask: downloadTask, didFinishDownloadingTo: location)
}
}
Copy the code
- This code typically passes through the binding we established earlier, through each proxy callback
task
Find the correspondingRequest
And then just pull it out because of the propertyRequest
Property delegate to handle related transactions
func urlSession(
_ session: URLSession,
downloadTask: URLSessionDownloadTask,
didFinishDownloadingTo location: URL)
{
temporaryURL = location
guard
let destination = destination,
let response = downloadTask.response as? HTTPURLResponse
else { return }
let result = destination(location, response)
let destinationURL = result.destinationURL
let options = result.options
self.destinationURL = destinationURL
do {
if options.contains(.removePreviousFile), FileManager.default.fileExists(atPath: destinationURL.path) {
try FileManager.default.removeItem(at: destinationURL)
}
if options.contains(.createIntermediateDirectories) {
let directory = destinationURL.deletingLastPathComponent()
try FileManager.default.createDirectory(at: directory, withIntermediateDirectories: true)
}
try FileManager.default.moveItem(at: location, to: destinationURL)
} catch {
self.error = error
}
}
Copy the code
- Transfer storage address after file download, file processing related and error condition
- The above is the most typical heavy disgusting operation, is certainly not need to be
SessionDelegate
All you need to know!
The process from SessionManager -> Request is explicitly delivered directly, but implicitly via the delegate response: SessionDelegate -> the delegate of the specific Request. See here, don’t you feel very cool! A good framework will always give you a big boost in terms of thinking, and we often have ugly couplings and communication issues. Then surely the design idea of Alamofire can bring you certain enlightenment!
Just ask who else is there right now? 45 degrees up in the sky, damn it! My charm with no place to put it!