IOS martial arts esoteric article summary
Writing in the front
Recently, I reread the source code of AFNetworking 4.x. Also combed some excellent code details and interview test points, listed down, found that this library is small and delicate, is the treasure of beginners.
AFN address in GitHub Secret Demo that may be used in this section
What about open source libraries?
First said a digression, reading high quality open source code library, is absolutely programmers quickly improve themselves effective way, and how efficient to read the source code is also a problem, I do not know whether there is and I before, encountered reading is read, but the total feeling harvest is not big.
Here are some of my code reading experiences:
-
Think more, ask more questions, like
- What is the overall code structure? What are the relationships between classes? Why do they do that?
- Does the code involve multithreading, and what is the threading model? What kind of problem applies to this multithreaded solution?
- What design patterns are used in the code? How does it work?
-
You can also pay attention to the details of the code, don’t let go of unfamiliar usage, more research to strengthen the foundation
Some of the best code details about AFNetworking have also been compiled here for review
-
Be sure to take notes and summarize. Sharing is even better
Referring to the Feynman method of learning, I think this is the best way to deepen understanding and strengthen memory. As memory declines with age, having a note to review can save you a lot of time memorizing it again. In addition, share more with people, and exchange verification, but also for their own shortcomings.
AFNetworking 4.x
Back to AFNetworking, the code structure of AF should be familiar to most people. Here I will briefly introduce it. The code structure of AFNetworking 4.x is much simpler than 2.x, mainly due to Apple’s optimization of the network related API. The overall code has the following parts:
NSURLConnection was removed from the AF3.x version
-
AFURLSessionManager/AFHTTPSessionManager
Here is the core of AF code, mainly responsible for network request initiation, callback processing, is a layer of encapsulation on the system network related API. Most of the logic is handled in AFURLSessionManager, which provides convenience methods for HTTP requests. If you need to extend the functionality of other protocols, such as FTP, consider creating a subclass from AFURLSessionManager.
-
AFURLRequestSerialization/AFURLResponseSerialization
The two brothers do some of the serialization work. AFURLRequestSerialization is introduced to the parameters of the structure into NSURLRequest, such as custom header, some post or get parameters and so on. AFURLResponseSerialization mainly will return to NSURLResponse processing system as we need responseObject, such as json, XML, image and so on.
-
AFSecurityPolicy
Handles HTTPS related public key and authentication logic. With the APPLE ATS enabled, basic HTTPS has become standard. Although it is common to use the CA directly to verify the server’s public key, no additional configuration is required. But from here on, by the way, HTTPS related knowledge is also common, specific interview questions can be read below
-
AFNetworkReachabilityManager
This is a separate module that provides the function of obtaining the current network state.
-
UIKit+AFNetworking
So this is basically just to provide a little bit of a convenience method of UIkit by Category
AFURLSessionManager/AFHTTPSessionManager
① Manager initialization
Speaking of manager initialization. I would like to ask you what is the design mode of Manager? I’m guessing a lot of people would say singleton, haha, if you say that in an interview, the interviewer will probably tell you to go back and wait. In fact, the design pattern used by manager is the factory design pattern.
Look at the parent classAFURLSessionManager
theinitWithSessionConfiguration
methodsAmong them, there is another test point oh. namelyself.operationQueue.maxConcurrentOperationCount = 1;
Why is that? Can we open a few more threads? —The answer is no
In view of the security concerns of some multithreaded data access. Meanwhile, Apple officially told us no
② Request method encapsulation
We all know that a complete request request should include the request line + the request header + the request body. Request lines will be covered later, but first, how AF encapsulates the header and body of the request.
In order toget
Let’s see, request for example, enterAF
In theget
Method of request implementationThis is basically returning onedataTask
andStart network request
, does not tell us how to encapsulate the request header, we continue to enterdataTaskWithHTTPMethod:
methodsThe main functions of this method are:
- 1.
To generate the request
- (2) by
request
generatedataTask
.
So how does it encapsulate the generated request? Keep up with my motorcade and continue inrequestWithMethod:
methods 在requestWithMethod
In the method, three things are done:
- (1) to create
mutableRequest
And set its request method; - ② Set some properties of the current class to
mutableRequest
—Configuration of the request header
;
If we do not set the timeout, we use the default timeout of 60 seconds...Copy the code
This is mainly usedKVO
Responsive programming techniques
- ③ Encode the parameters to be passed and set to
mutableRequest
–Request parameter encapsulation
, the callrequestBySerializingRequest:
methods
This method mainly does the following things:
- ① Fetch from the current request queue
self.HTTPRequestHeaders
To the parameter to be requestedrequest
In the. - (2) the
Network request parameters
convertNSString
Type, that’s the right stepParameters are transcoded
— This is our focus, mainly callAFQueryStringFromParameters
Methods. - ③ Concatenate the request method to
url
In:GET, HEAD, DELETE
This a fewmethod
thequery
Is spliced intourl
In the back, andPOST, PUT,
Is thequery
Joining together tohttp body
In the.
Now let’s focus on,AF
How to convert the parameter dictionary we passed into a string. Enter theAFQueryStringFromParameters
methodsCall recursively and parse until nothing is parsedArray, DIC, set
Then return the final parameter, and proceed with step ③.
③ The relationship between task and agent
And then the above analysis, which we just didAF
How to makeNetwork request parameters
convertNSString
Type, now let’s seeAF
How do you concatenate request methods tourl
This brings us to our main pointtask
withThe agent
Enter intodataTaskWithRequest:
methods One thing to notice here is that this method is made up ofAFURLSessionManager
Managed, not managedAFURLSessionManagerTaskDelegate
So why are they connected and connected in the end? Want to know? Let’s move on if you wantIn combination with the previous we have the holding relationship at this timemanager-->session-->task--->delegate--->manager
Doesn’t that make a circular reference? How does AF solve this problem? And then back to ours
After the above process, the call is next[dataTask resume];
Method. Thisresume
There is a problem, iron,AF
There are some dirty operations on it at the bottom.. Here I will reveal his secret. He actually made an inner class here_AFURLSessionTaskSwizzling
, in this class willresume
andaf_resume
It’s an exchange. Let’s take a lookAF
Make SAO operationaf_resume
The implementation of theIn fact, in this caseAF
Inside the frame, we can get it alltask
Status. who is this notification for? Let’s have a lookTo theAFURLSessionManager
.because it is a big butler, a lot of authority. Ha ha.
Finally, to summarize the whole process of this part, as shown below
AFURLRequestSerialization/AFURLResponseSerialization
① NSObject, NSSecureCoding, NSCopying protocol
Came toAFURLRequestSerialization
Class declaration address, we’ll see that it followsNSObject, NSSecureCoding, NSCopying
These three protocols.Mainly is to letAFURLRequestSerialization
havecopy
andThe archive
And a series of functions.
② Data encapsulation of multiple forms
What about multiple forms? To look directly at the source codeEnter via the above method (called when uploading an image or a breakpoint continues)multipartFormRequestWithMethod:
methodsLet’s start with productionformData
theinitWithURLRequest:
methodsLet’s seeAFCreateMultipartFormBoundary
This delimiterAnd then let’s go back and continueAF
Is how to deal withparameters
It will perform a series of formatting to generate the correspondingAFQueryStringPair
Yeah, and then finally the concatenation callappendPartWithFormData
methods
The whole process is going to be
Notice hereMore than the form
theContent-Type
And the generalpost
Forms are different and commonContent-Type
is 而More than the form
It is Let’s seecontentLength
How is it put together
(2) the Stream flow
So how is the data processed after stitching? So let’s go backThat’s set in this methodstream
.Let’s take a look firstHTTPBodyStream
attributeSource code tells usstream
It’s off by default, so we’re going to turn it on before we read it. And then after callingNSInputStream
Relevant agents. 且HTTPBodyStream
andHTTPBody
It is incompatible. Only one can be set.
In the callresume
Method is preceded by the following method.This method is mostly calledbodypart
Interface method:read:... maxLength
Then enter thetransitionToNextPhase
In this method we open ourstream
thentransitionToNextPhase
When is this method called? Actually it is ininit
It’s called when it’s initialized
(3) AFURLResponse
So when is it comingAFURLResponse
?Manager -- task -- Request completion
When the background has a return time. Go back toNSURLSessionTaskDelegate
In the proxy methodif(error)else
Part of theThis includes various serializations that we are developingLet’s see what we use[AFJSONResponseSerializer responseObjectForResponse:data:error:]
methods
- First look at the verification request judgment piece, he is to verify what?
- ② If the verification is passed, it will be carried out
JSON
Data serialization, there’s one thing that needs to be said about this
Removes data that is returned as null.
The flow of this section is roughly as follows
AFSecurityPolicy
(1) introduction of HTTP
(2) the HTTPS
The difference between HTTPS and HTTP
HTTPS = HTTP + SSL/TLS SSL is a Secure protocol that provides security and data integrity for network communication. TLS stands for Transport Layer Security. That HTTPS is secure HTTP.
HTTPS connection establishment process
HTTPS uses both symmetric and asymmetric encryption to ensure security and efficiency. Three keys are involved in the transmission process:
-
The public and private keys on the server are used for asymmetric encryption
-
Random key generated by the client for symmetric encryption
As shown in the figure above, the HTTPS connection process can be roughly divided into eight steps:1. The client accesses the HTTPS connection
The client sends the security protocol version number, list of encryption algorithms supported by the client, and a random number C to the server.
2. The server sends the certificate to the client
After receiving the key algorithm accessory, the server compares it with the list of supported encryption algorithms. If the list does not match, the server disconnects from the server. Otherwise, the server selects a symmetric algorithm (such as AES), a public key algorithm (such as RSA with a specific key length), and a MAC algorithm from the algorithm list to send to the client. The server has a key pair, that is, a public key and a private key, which are used for asymmetric encryption. The server stores the private key and cannot disclose it. The public key can be sent to anyone. The digital certificate and random number S are sent to the client when the encryption algorithm is sent
3. The client authenticates the server certificate
The server public key is checked to verify its validity. If the public key is faulty, HTTPS transfer cannot continue.
4. The client assembles the session key
If the public key is qualified, the client will use the server public key to generate a pre-master Secret (PMS), and assemble the session Secret from the pre-master key and random numbers C and S
5. The client encrypts the former master key and sends it to the server
The former master key is asymmetrically encrypted through the public key of the server and sent to the server
6. The server decrypts the former master key through the private key
After receiving the encrypted message, the server decrypts it with the private key to obtain the master key.
7. The server assembles the session key
The server assembles the session key from the pre-master key and random numbers C and S. At this point, both the server and client know the master key for the session.
8. Data transmission
The client receives the ciphertext sent by the server and decrypts it symmetrically using the client key to obtain the data sent by the server. Similarly, the server receives the ciphertext sent by the client and decrypts it symmetrically using the server key to obtain the data sent by the client.
Conclusion:
Session key = random S + random C + former primary key
-
The ESTABLISHMENT of HTTPS connections uses asymmetric encryption, which is a time-consuming encryption method
-
Symmetric encryption is used in subsequent communication to reduce performance loss caused by time consumption
-
Symmetric encryption encrypts actual data, while asymmetric encryption encrypts client keys required by symmetric encryption.
Symmetric and asymmetric encryption
1, symmetric encryption
Use the same set of keys to encrypt and decrypt. Symmetric encryption usually includes DES,IDEA, and 3DES encryption algorithms.
2, asymmetric encryption
Encryption and decryption algorithms using public and private keys. A Public Key and a Private Key are a Key pair (namely, a Public Key and a Private Key) obtained through an algorithm. The Public Key is the Public part of the Key pair, and the Private Key is the Private part. The Private Key is usually stored locally.
-
Encrypting with public key requires decrypting with private key. Whereas encryption with a private key requires decryption with a public key (digital signature).
-
Asymmetric encryption is secure compared to symmetric encryption because the private key is stored locally.
However, asymmetric encryption takes up to 100 times more time than symmetric encryption, so it is usually used in combination with symmetric encryption.
Common asymmetric encryption algorithms include RSA, ECC (for mobile devices), Diffie-Hellman, El Gamal, AND DSA (for digital signature).
In order to ensure that the client can confirm that the public key is the public key of the website they want to visit, the concept of digital certificate is introduced. Since there is a certificate issuing process at the first level, a certificate chain appears, and the root CA is at the top of the certificate chain.
(3) AFSecurityPolicy
Take a look atAF
The source of
So how does it get the public key? Continue to follow upsetPinnedCertificates
methodsThere are two possible authentication modes during public key acquisition: unidirectional authentication (server) and bidirectional authentication (customer and server): All certificate information is verified during the public key transfer process. This will be entered later in the proxy methodevaluateServerTrust:forDomain:
Method to verify that the server is trustworthy.If your certificate is untrusted, he will enterThat is, if your certificate isCA
Do not need to be processed, is a self-signed need to set as the root certificate.
AFNetworkReachabilityManager
Let’s start with a flow chartWithout further discussion of the source code, this class mainly uses the global singleton design patternThen callmanager
methodsTo follow upmanagerForAddress
methods
returnReachabilityManager
Object after callstartMonitoring
methods And then according to the networkflag
Convert to the network state calls we use in developmentAFNetworkReachabilityStatus()
UIKit+AFNetworking
AFAutoPurgingImageCache
This class is used to manage cached images in memory. It provides the maximum memory capacity and the preferred memory capacity. When the maximum memory capacity is reached, the oldest unused cached images are purged until they fall below the preferred memory capacity. Let’s see how this function is implemented.
AFImageCache agreement
This protocol defines methods for adding, deleting, modifying, and viewing cached images. These methods are synchronized and secure:
@protocol AFImageCache <NSObject>
- (void)addImage:(UIImage *)image withIdentifier:(NSString *)identifier;
- (BOOL)removeImageWithIdentifier:(NSString *)identifier;
- (BOOL)removeAllImages;
- (nullable UIImage *)imageWithIdentifier:(NSString *)identifier;
@end
Copy the code
These methods involve the input parameter identifier, which can be used as the image ID to find the image, generally represented by the image name. Of course, the network image can also be represented by THE URL. For this point, AF extended this protocol.
AFImageRequestCache
@protocol AFImageRequestCache <AFImageCache>
// The default implementation is YES
- (BOOL)shouldCacheImage:(UIImage *)image forRequest:(NSURLRequest *)request withAdditionalIdentifier:(nullable NSString *)identifier;
/ / add and check methods, support the incoming a request object, and to request the URL. AbsoluteString identifier for the picture, at the same time can also be splicing AdditionalIdentifier after the default identifier
- (void)addImage:(UIImage *)image forRequest:(NSURLRequest *)request withAdditionalIdentifier:(nullable NSString *)identifier;
- (BOOL)removeImageforRequest:(NSURLRequest *)request withAdditionalIdentifier:(nullable NSString *)identifier;
- (nullable UIImage *)imageforRequest:(NSURLRequest *)request withAdditionalIdentifier:(nullable NSString *)identifier;
@end
Copy the code
After looking at the definition of the protocol, let’s move on to the AFAutoPurgingImageCache class, the main implementation of the protocol
AFAutoPurgingImageCache
In addition to implementing AFImageCache protocol related methods, this class also adds memory control properties:
// Maximum memory
@property (nonatomic.assign) UInt64 memoryCapacity;
// Preferred memory
@property (nonatomic.assign) UInt64 preferredMemoryUsageAfterPurge;
// Current memory usage
@property (nonatomic.assign.readonly) UInt64 memoryUsage;
// init
- (instancetype)initWithMemoryCapacity:(UInt64)memoryCapacity preferredMemoryCapacity:(UInt64)preferredMemoryCapacity;
Copy the code
Properties are easy to understand. How these properties are used depends on the implementation:
@interface AFAutoPurgingImageCache(a)
// A dictionary to manage cached images
@property (nonatomic.strong) NSMutableDictionary <NSString* , AFCachedImage*> *cachedImages;
// Memory currently in use
@property (nonatomic.assign) UInt64 currentMemoryUsage;
// Secure the queue
@property (nonatomic.strong) dispatch_queue_t synchronizationQueue;
@end
Copy the code
The key of this dictionary is the identifier of the image and the value is the AFCachedImage object. For this object, let’s look at its implementation:
@interface AFCachedImage : NSObject
@property (nonatomic.strong) UIImage *image;//持有image
@property (nonatomic.copy) NSString *identifier;// Unique identifier
@property (nonatomic.assign) UInt64 totalBytes;// The total number of bytes used by the image
@property (nonatomic.strong) NSDate *lastAccessDate;// The time of the last fetch
@property (nonatomic.assign) UInt64 currentMemoryUsage;// Memory currently in use
@end
@implementation AFCachedImage
- (instancetype)initWithImage:(UIImage *)image identifier:(NSString *)identifier {
if (self = [self init]) {
self.image = image;
self.identifier = identifier;
// Count the total number of bytes of the current image
CGSize imageSize = CGSizeMake(image.size.width * image.scale, image.size.height * image.scale);
CGFloat bytesPerPixel = 4.0;
CGFloat bytesPerSize = imageSize.width * imageSize.height;
self.totalBytes = (UInt64)bytesPerPixel * (UInt64)bytesPerSize;
self.lastAccessDate = [NSDate date];
}
return self;
}
- (UIImage *)accessImage {
// The time is refreshed every time the image is retrieved
self.lastAccessDate = [NSDate date];
return self.image;
}
@end
Copy the code
You can seeAFCachedImage
Class equivalent to pairUIImage
Wrapped it up, added some attributes that identify the class, and now we’re backAFAutoPurgingImageCache
Read on to see how it is implemented: The above isAF
Image cache, the general process is
AFImageDownloader
Download the image class. This class will download the image task in parallel, and the downloaded image will be cached in memory. The most common method we use is to set up images for UIimageView, which also needs to use THE AF UIimageView +AFNetworking classification. For example [cell imageView setImageWithURL: [NSURL URLWithString: model. The imageUrl]].
This time will comeAF
theUIImageView+AFNetworking
Classification ofsetImageWithURL:
methodswhyAFImageDownloader *downloader = [[self class] sharedImageDownloader];
usingsharedImageDownloader
? It means all my downloads can be downloaded from a single downloader. This downloader is associated withAF
Class, so set it with association properties.A download credential is then initializedAFImageDownloadReceipt *receipt;
Download credentials will be calleddownloadImageForURLRequest:
methodsTo sort out the general logic, when we need to load the network picture, we calldownloadImageForURLRequest
Method to create a task and generatereceipt
Return it to us so we can cancel at any time. During the loading process, the user preferentially selects whether to search in the cache according to the cache policy. After the request is successful, the current image will be stored in the memory for next use.
AF
The general process of downloading images is as follows
Some good code details for AF
After a careful look at the code, I found that common OC basic knowledge has specific application in AF, and most of them are also the interview questions. Here I also make a record and sort out.
- How to create a singleton
throughdispatch_once
To ensure that only one instance is created when a multithreaded call is made.
- Dispatch_sync and dispatch_barrier_sync work together to solve parallel read and write problems
GCD
usebarrier
To deal withParallel reading serial writing
The specific usage of the question
- WeakSelf and strongSelf usage — strong and weak dance together
Must know must know,weakSelf
Avoid circular references,strongSelf
ensureblock
Internal execution processself
Will not be released.
Possible interview sites for AFNetworking
As mentioned above, when reading the open source library, you should think more and ask more questions. Here are also some interview questions to comb through
AFNetworking 2.x how to start resident child thread? Why do WE need resident child threads?
Af2. x has a detail that starts a resident child thread with runloop. The code looks like this:
+ (void)networkRequestThreadEntryPoint:(id)__unused object {
@autoreleasepool{[[NSThread currentThread] setName:@"AFNetworking"];
NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
[runLoop addPort:[NSMachPort port] forMode:NSDefaultRunLoopMode]; [runLoop run]; }} + (NSThread *)networkRequestThread {
static NSThread *_networkRequestThread = nil;
static dispatch_once_t oncePredicate;
dispatch_once(&oncePredicate, ^{
_networkRequestThread = [[NSThread alloc] initWithTarget:self selector:@selector(networkRequestThreadEntryPoint:) object:nil];
[_networkRequestThread start];
});
return _networkRequestThread;
}
Copy the code
First, why do we want to start resident child threads?
The NSURLConnection interface is asynchronous and then initiates a thread callback. A child thread, on the other hand, usually exits after the synchronous code is executed. In order to receive a callback from NSURLConnection, the child thread must survive at least until the time of the callback. The reason AF keeps the thread resident is that when multiple HTTP requests are made, the child thread will be called back to, so it simply stays alive.
Under what circumstances can a child thread continue to live? This brings us to the second question, how AF starts resident threads, which is really looking at the basics of Runloop.
For runloop, check out my iOS Hack at ⑲: Memory Management and NSRunLoop. To put it simply, the runloop does not exit when it finds a source/timer/observer. So AF adds an NSMachPort to the current runloop. This port actually adds a source event source, so that the thread’s runloop stays in a loop waiting for another thread to send a message to the port. In fact, AF has no message sent to this port.
In addition to the AF approach, Apple actually provides a callback thread solution:
// NSURLConnection
- (void)setDelegateQueue:(nullable NSOperationQueue*) queue
// NSURLSession
+ (NSURLSession *)sessionWithConfiguration:(NSURLSessionConfiguration *)configuration delegate:(nullable id <NSURLSessionDelegate>)delegate delegateQueue:(nullable NSOperationQueue *)queue;
Copy the code
Apple provides interfaces that allow you to make oneoperationQueue
For callback executionAF3.x
At the beginning of the version, one is created directlyThe concurrency is 1
To process the callback.
Extend one:
The interviewer may ask you: Why did you start fromAF3.x
You need to set it upmaxConcurrentOperationCount = 1
And theAF2.x
Don’t need it?
This is not a difficult question, but it can help the interviewer determine whether the candidate has really studied the source code for the two large versions of AF. Answer: Different functions: AF3. Start x operationQueue is used for receiving NSURLSessionDelegate callback, in view of some multi-threaded data access security considerations, set the maxConcurrentOperationCount = 1 to achieve the effect of serial callback. Af2. x’s operationQueue is used to add operations and make concurrent requests, so do not set it to 1.
The relationship between AFURLSessionManager and NSURLSession. Do I need to create a new Mananger every time?
If we look closely at the code, we should be able to conclude that the manager and session have a one-to-one relationship, and AF will create the corresponding NSURLSession when the Manager is initialized.
So reusing manager is actually reusing session, and what benefits can reusing session bring?
Session support for http2.0 has been around since iOS9. One of the features of http2.0 is multiplexing. Reusing sessions takes advantage of the multiplexing features of HTTP2.0 to reduce the time and resources required to re-establish TCP connections when accessing the same server.
The official document also recommends using different sessions for different functional scenarios. For example, one session handles normal requests and one session handles background requests. One session handles requests made public by the browser, one session handles privacy requests and so on.
How does AFSecurityPolicy avoid man-in-the-middle attacks?
Now, because of the Apple ATS policy, basically cut to HTTPS, the basic principle of HTTPS still need to understand, not here, you can Google related articles.
In general, the first thing we need to understand is a man-in-the-middle attack, basically a hacker intercepts the certificate returned by the server and forgeries his or her own certificate. Often tools like Charles/Fiddler that we use can actually be considered a man-in-the-middle attack.
The solution is actually quite simple, the AFSSLPinningMode of SSL tunneling.AFSecurityPolicy is the related setup.
SSL Pinning
Is that you need to package the server’s public key into the client,tls
During authentication, the server certificate is compared with the local certificate. If the certificate is the same, authentication is allowed.Because a digital certificate has a validity period, authentication may fail after it is invalidated after being embedded in the client. Therefore, you can set it toAFSSLPinningModePublicKey
In this case, as long as the certificate is renewed, the public key in the certificate does not change, can pass the authentication.
Write in the back
Study harmoniously without being impatient. I’m still me, a different color of fireworks.