In-depth analysis of Alamofire source code in iOS development, iosalamofire
The Alamofire source code version in today's blog is the latest3.4The version is used as an example. The previous Blog system detailed NSURLSession-related things. For more information, see "Detailed NSURLSession" to lay the foundation for this blog. AlamoFire further encapsulates NSURLSession and related things, making it easier to use network requests. This blog will look at the AlamoFire source code in detail, mainly to see how AlamoFire encapsulates NSURLSession, and to see which Swift languages are used in encapsulation for advanced usage, that is to say, let's take a look at the further use of the Swift language.
Of course, AlamoFire is the Swift version of AF. Although it is implemented in the Swift language, the implementation idea is similar to AFNetWorking. If you have read the AFNetWorking source code before, you should be familiar with Alamofire source code. The Implementation ideas in many places are consistent. Today's blog does not teach you how to use AlamoFire, but shows you how Alamofire is implemented. This blog is full of good news. for the official AlamoFire documentation, please go to Alamofire-github link.
The class diagram in the first part below is a simple class diagram drawn to sort out the relationship between each structure when reading the AlamoFire source code. The class diagram below does not cover all the classes in AlamoFire, it gives the modules of the core part and the relationship between each module. Next, we will split the modules below and break them apart. The topic of this blog is to first take a look at AlamoFire's organizational structure and parse the relationship between each part. Then, we will analyze each module in detail. During the parsing, We will extract some knowledge points of the Swift language and analyze them.
1. Alamofire core module Overview
Let's take a look at the framework relationship of AlamoFire and outline some core modules. In this section, we will first look at the file organization structure of AlamoFire, and then give the class relationship in these file organization structures. Therefore, the classification chart in this section is indispensable. The topic of this part.
1. Alamofire directory structure Parsing
First, let's take a look at AlamoFire's directory structure and take control of AlamoFire as a whole. Below are all files of the AlamoFire framework. There are not many files, and the source code of the Alamofire framework is not much. It is not difficult to clarify the structure of the Alamofire framework. All files in AlamoFire are listed below, and the Core folder is the Core file of Alamofire. Features is mainly used to expand the Core file. Today, we will focus on the core file, supplemented by the Feature file, to explore the source code of the AlamoFire framework.
Below is a brief description of the functions of each file in the Core Folder:
Alamofire. swift-this file mainly provides users with convenient calling methods. Users can directly call the convenient methods in this file to use Alamofire-related functions.
Manager. swift ---- the Manager defines the Session object, Session-related Delegate, and the queue that the Delegate executes, and creates a Request object in the Manager to initiate a Request. The Manager manages various requests, and the Manager object is open to the outside in the form of a singleton.
Request. swift ---- the file is named as it is responsible for creating various tasks of the Session and executing the relevant SessionTask, the function module of parsing related books is called to parse the data and return the data to the user through callback.
ParameterEncoding. swift ---- It is responsible for encoding of request parameters (URL, URLEncodedInURL, JSON, PropertyList, etc.), and returning the encoded data combined with URLRequest.
Result. swift ---- encapsulate the parsed data into a Result object.
Response. swift ---- encapsulate the corresponding data on the server to generate a Response object, which includes the above Result object. The user will finally get the Response object through the closure callback.
Notifications. swift-a Notification struct that defines strings that are the keys to be notified. Notifications are sent when network requests DidResume, DidSuspend, DidCancel, and DidComplete are sent.
Error. swift ---- A structure of Error, which encapsulates various Error states.
Functions of each file in the Features Folder:
Download. swift ----- extends the Manager and Request classes to support Down tasks. This encapsulates NSURLSessionDownloadDelegate-related proxy methods.
Upload. swift ---- this file also extends the Manager and Request classes to support Upload tasks. It encapsulates the proxy method for obtaining the Upload data progress in NSURLSessionDataDelegate, that is, the taskDidSendBodyData proxy method.
MultipartFormData. swift-the file is named to organize the data uploaded from multiple forms. MultipartFormData is used in the Upload Task.
Stream. swift ---- similar to the Download and Upload files, this file also extends Manager and Rquest to support data stream transmission. It encapsulates and implements NSURLSessionStreamDelegate-related proxy methods.
ResponseSerialization. swift ---- this file mainly extends the data parsing for the Request class. It encapsulates various Resolution Methods for response Data, including Data, String, JSON, and PropertyList.
NetworkReachabilityManager. swift ---- this file encapsulates SCNetworkReachability in SystemConfiguration. framework and manages and monitors network status changes.
ServerTrustPolicy. swift-this file mainly extends NSURLSession, which defines the authentication policies for various network requests, and mainly related to certificate authentication.
Timeline. swift-this file is generated for debugging convenience. It records the time points of related operations and records them for ease of use during debugging.
Validation. swift ---- it is mainly used to verify whether the request is successful. If an error occurs, it will be processed accordingly.
The above is an overview of all files in AlamoFire. The above is a rough understanding of the AlamoFire framework. It is clear to study AlamoFire source code based on the above overview. Below is the wood structure of related files in AlamoFire 3.4, as shown below:
2. Structure between core classes
The preceding section briefly introduces the directory structure of the Alamofire framework and the content of each file. Next we will go to the interior of each file to take a look at the relationships between core classes as a whole. Below is the "class diagram" of the core class, of course, the bottom is only the core class. Next, we will outline the class diagram under the category. Because it is too large, it does not seem clear here. If you are interested, you can save it as a class diagram and zoom in to view it.
The content in the black box below corresponds to the content in Alamofire. swift. It mainly refers to the extension of URL conversion strings and the extension of URLRequst conversion to MutableURLRequest, as well as some convenient methods for users.
The yellow box is our Manager. in swift, the Manager class objects are displayed in the form of singleton. The convenience method in the black box above is mainly to obtain the singleton of Manager class and then call the corresponding method.
The Green Box corresponds to the content in the Request. Swift and Features folders, mainly the Request class and its extension, and of course the extension of Manager and NSURLSession.
The red box encapsulates the callback methods for various tasks in the network request session. The default implementation is provided in these callback methods, and the callback block is left externally, this allows you to implement these callback methods on your own.
Ii. Alamofire. swift source code parsing
The first part is an overview of the various components in the Alamofire framework. Next, we should go to the above modules to further explore their implementation and organization methods. Let's start with what the user sees and go deeper until you can't see it. So let's take a look at the second part.Alamofire. swiftBecause the file is the entrance to the Alamofire framework.
Class graph structure in 1.Alamofire.swf t
The class diagram below is an enlarged version of the black box in the first classification diagram. According to the Alamofire. swift file, it is not difficult to draw the class diagram below. One thing to note is that some traversal methods are omitted in the class diagram and only some primary functions are written, but the core functions are still available. URLStringConvertible and URLRequestConvertible below are interfaces responsible for type conversion. For details, refer to the introduction below. In addition to the type conversion method, this file is a convenient method for calling the Manager Singleton.
2. Alamofire. swift technical details
Below is the specific implementation of the URLStringConvertible Protocol and related extensions. The main function is to convert the URL in String, NSURL, NSURLComponents, and NSURLRequest to the String type. The type to be converted must follow the URLStringConvertible protocol and return the converted string in the calculated URLString. The specific method is as follows. This type conversion method is often used in development. Other instances are provided below. The functions of URLRequestConvertible are similar to those of URLStringConvertible. the implementers of URLRequestConvertible are responsible for converting NSURLRequest to NSMutableURLRequest. I will not repeat it too much here.
Below is Alamofire. A convenient method in swift. Several other convenient methods are similar to this. They call the corresponding methods in the Manager singleton. Convenient Methods call the relevant methods in the Request class in a chain, therefore, all convenient methods will return the Request object used by the current Manager Singleton. The details are as follows:
3. Extended use cases
What you have learned is the opposite. The above idea of "protocol-oriented" Development is worth learning. Previously, I mentioned "interface-oriented programming" more than once in a series of blogs related to design patterns. The protocol here is interface. Although the above is just a simple type conversion using protocols, this idea is worth learning. With the above type conversion method, we can write the following code. The code below is not the code in the Alamofire framework. It is implemented based on the above type conversion instance. The following defines a type conversion protocol and the type to be converted must follow this protocol, the following uses String as an example. The procedure is as follows.
Iii. Manager. swift source code parsing
Because the convenience method is mainly a singleton of the called Manager class, let's take a look at the things in Manager. swift. The Manager class initializes sessions and requests, and provides the default implementation of the SessionDelegate proxy method. When implementing the proxy method, the corresponding closure has been provided to users to call the corresponding proxy method back and forth using this closure. In Manager, The SessionDelegate class is the NSURLSessionDelegate class and the proxy class of related sub-protocols. The default implementation of each proxy method is provided, and a series of Closure callback variables are defined during implementation, when these closure variables are not empty, the content in the closure block will be executed, rather than the provided default implementation.
1. Manager. swift related class diagram
The class diagram below is an enlarged version of the yellow part, mainly the relationship between the Manager class and SessionDelegate. It is not difficult to see from the class diagram below that the SessionDelegate class complies with the NSURLSessionDelegate protocol and sub-protocol, and provides corresponding proxy implementation methods. The code below provides specific proxy encapsulation and implementation methods.
2. related attributes of the Manager class
As the Manager class is used externally in the form of a Singleton, let's take a look at the singleton Implementation of the Manager class. The sharedInstance calculation attribute below is the Manager Singleton, where a Manager object is stored, when creating a Manager object, we specify a defasessessionconfiguration and a defaultHTTPHeaders for the NSURLSession object stored in the Manager object.
The above is the implementation of a single example in the Manager class. Next we will resolve the core attributes in the class. below is the analysis of some core attributes:
DefaultHTTPHeaders attribute: defaultHTTPHeaders is a computing attribute in the Manager class and organizes the content in the default request Header.
Session attribute: The NSURLSession type is used to request sessions and create various session tasks.
Queue attribute: This attribute is a serial queue that executes the Task of creating session tasks in sessions.
Delegate attribute: This attribute belongs to the SessionDelegate type, while the SessionDelegate class complies with NSURLSessionDelegate and its sub-protocols, and provides corresponding implementations. The following describes SessionDelegate. The delegate attribute is used to call the corresponding callback method in the SessionDelegate class.
3. The request method of the Manager class
The implementation of the request method is provided in the Manager. swift source file. The upload and download methods called by the Manager class Singleton are extended in other source files. The extended methods will be discussed later. In this section, we will first parse the request method. The following method is called by the Manager class Singleton in the convenience method. The method parameter indicates the Request method (GET, POST, PUT, etc.), the URLString parameter indicates the request address, and the parameter indicates the request parameter. The encoding parameter is the encoding method of the request parameter. The default value is URL encoding. The headers dictionary parameter is the request header information. The default value is nil. The following code creates an NSMutableURLRequest object, encodes the parameter, adds it to the NSMutableURLRequest object, and calls the request () method to initiate a request.
The code segment below is the request () method called in the above function. The request () method below is used to create a dataTask through the Session, that is, to execute a Data Task. Then, when initializing the Request object, pass the created Data Task object to the Request object. Then, the Task Delegate object of the Request object is stored in the delegate attribute of the Manager class. Because the proxy method in the delegate attribute calls the corresponding Task Delegate method, it is necessary to store it here. Then, call the resume () method of the Request object to initiate a network Request for data. To call other methods of the Request object in a chain, the object of the Request class is returned. The Code is as follows:
4. SessionDelegate parsing in Manager
SessionDelegate can be said to be the proxy, because SessionDelegate has a subdelegates dictionary attribute, which stores each Task Delegate in the Request object. SessionDelegate calls the method in Task Delegate through the stored Task Delegate in the corresponding proxy method, so SessionDelegate is the proxy.
The code segment below is part of the code in the SessionDelegate class. The subdelegates dictionary attribute stores the TaskDelegate in the Request, and the subdelegateQueue is a parallel queue used to synchronously obtain and set the Task Delegate object in the dictionary. The subscripts are defined for the SessionDelegate class. The subscripts are used to add and obtain the corresponding Task Delegate from subdelegates in the form of Session tasks. This custom subscript allows the class object to set and obtain the attribute value in the form of a lower mark. The extended Demo will be provided later.
For the proxy method implemented in SessionDelegate, here we take the didReceiveData proxy method for executing the Data Task request as an example. Below is the didReceiveData proxy method in SessionDelegate. The code is relatively simple. First, determine whether the Closure callback variable of the proxy method object has a value. If yes, execute the Closure callback block. If no value exists, obtain the Data Task Delegate we store, then execute the didReciveData method in the Data Task Delegate. Other methods are similar, so we will use vertices to represent the surface, so we will not repeat it too much here.
5. knowledge point extension
The next step is to expand the knowledge point. Next we will create a small instance separately to see how the custom subscript in Swift works. Next we will simplify the use of the above-mentioned icons, create a Demo, and use this Demo to introduce the use of the following icons.
The code snippet below is a simple version of subscript example we created. The Swift class supports custom subscripts, allowing you to access and set attributes in the following standard form. A subscript is defined below to set and return the value of the value attribute in the lower mark. The usage is as follows:
Iv. Request. swift source code parsing
Gradually deepen, we now come to Request. swift class, because the Request in the Manager above finally reaches the position of the Request class, what we need to analyze next is Request. content in the swift source file. In the Request. swift source file, the Data Task Request is executed and the method in the Data Task Delegate is implemented. Other tasks, such as Download Task, Upload Task, and Stream Task, will execute the preceding tasks when the Request is extended in other files. Here we take Data Task as an example. In the Request class, it is responsible for creating the corresponding Task through the session and implementing the proxy method of the corresponding Task.
1. Request-related class diagram
The following class diagram shows the Request-related class diagram. In the Request class and its extension, various types of tasks are created and the corresponding Task Delegate is given. The class diagram below also provides an inheritance relationship between various Task Delegate. When the source file related to the Request provides the implementation of the TaskDelegate proxy method, it also encapsulates the callback method in the closure state. This is the same as SessionDelegate. The following is a detailed introduction.
2. Request class initialization method
Below is the Request class initialization method. The method requires two parameters. The first parameter is the NSURLSession object, which is the Session object created in the Manager Singleton. Although the second parameter is passed by the Manager, the task for task initialization must be handed over to the Request class. The Manager only defines the type of an NSURLSessionTask and transmits it to the Request, for example, in the request () method of the Manager, the task type is NSURLSessionDataTask, and the task type in the upload () method of the Manager is NSURLSessionUploadTask.
In the Request initialization method, the task type provided by the Manager Singleton is determined to create DataTaskDelegate and UploadTaskDelegate. The corresponding Task is created in the corresponding Task Delegate. The preceding DataTask is used as an example. If you call the request () method in the Manager Singleton, the initialization of DataTaskDelegate () is executed. As follows:
The preceding delegate is of the TaskDelegate type, because UploadTaskDelegate, DownloadTaskDelegate, and DataTaskDelegate are all subclasses of TaskDelegate, so object-oriented "polymorphism" is used here ". The following two attributes are the delegate and task attributes in the Request class. The delegate is initialized in the preceding Requset initialization method, and the task here is a storage attribute, task Initialization is placed in the corresponding TaskDelegate. After a task object is created in TaskDelegate, the task attribute in the Request class is assigned as follows:
3. Progress closure in the Requset class
When using an object in the Request class, we can chain the methods in the Request, the most common is to get the progress of the corresponding task execution, that is, the progress () method I usually use. The code snippet below is the implementation of the progress () method. Determine which Task is currently executed by using the Task Delegate type, and assign the passed SS closure to the corresponding Task Delegate, in the Delegate of these tasks, the Task execution progress is obtained in the corresponding callback method, and the Closure passed in below is executed.
4. Request's resume () method
Below is the resume () method in the Request class, where the code is relatively simple. It is mainly used to record startTime and then call the resume method of the task to start executing the task. Of course, you must initiate a notification after you start executing the task. Here, the DidResume notification is sent. All notification types are stored in the Notifications struct in the Notifications. swift file. The implementation of other methods in the Request class, such as suspend () and cancel () methods is similar to resume (), and the corresponding notifications are sent, so we will not repeat them too much here.
5. Related proxy classes in the Request class
From the class diagram in the first part, we can see the proxy class related to the Request class. TaskDelegate is the base class of all proxy classes. In this proxy class, it defines the necessary attributes and the corresponding callback methods in NSURLSessionTaskDelegate, and provides the corresponding closure callback form for these callback methods. The following uses the TaskDelegate proxy class as an example. Below is the Closure method provided by the TaskDelegate proxy class for the corresponding proxy method in NSURLSessionTaskDelegate. Other proxy classes such as DataTaskDelegate and DownloadTaskDelegate are similar. In the corresponding proxy method, the callback is processed. However, before processing, the system determines whether the corresponding Closure is nil. If it is not nil, the Closure block is executed. If it is nil, the default processing is performed.
The core classes in Alamofire have been introduced. Due to limited space, other classes will not be described too much here. The content of other classes and other files is outlined in the first part. The internal implementation details are not described too much, the Code shared on Github gives a comment on the key technical details of these classes.
In the Alamofire framework, extended, closure, and enumerated correlated values are widely used. In particular, when parsing network request data, we take the closure type as a function parameter, and then use the closure variable to provide the corresponding resolution scheme, so we will not repeat it too much here, other technical details are "benevolent and wise ". Listen to me and read more technical blogs. If you don't know more about it yourself, it's useless to say more about it. Other content about Alamofire source code will not be described too much here. If you are interested, read it in person. You are welcome to communicate with each other. Today's blog is here.
Github share link: https://github.com/lizelu/iOS_NetWorkingAndAlamofire