AFURLSessionManager/AFHTTPSessionManager parsing
The AFN structure
AFNetworking
- The core
AFURLSessionManager
AFHTTPSessionManager
- serialization
AFURLRequestSerialization
AFHTTPSerializer
AFJSONRequestSerializer
AFPropertyRequestSerializer
AFURLResponseSerialization
AFHTTPResponseSerializer
AFJSONResponseSerializer
AFXMLParserResponseSerializer
AFXMLDocumentResponseSerializer(macOS)
AFPropertyListResponseSrializer
AFImageResponseSerializer
AFCompoundResponseSerializer
- Auxiliary class
AFSecurityPolicy
AFNetworkReachabilityManager
The UI class
.
Initialization of AFHTTPSessionManager
AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
AFHTTPSessionManager Initializes the internal process
1.
Layer by layer to the parent class(AFURLSessionManager)
The initialization method of
- (instancetype)initWithSessionConfiguration:(NSURLSessionConfiguration *)configuration;
- Gets or creates defaults
configuration
And hold
if(! configuration) { configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
}
self.sessionConfiguration = configuration;
Copy the code
- Initialize the serial queue (
serial queue
, apple documentation requires, to make sure the callbacks are in the correct order), for generationsession
self.operationQueue = [[NSOperationQueue alloc] init];
self.operationQueue.maxConcurrentOperationCount = 1;
Copy the code
- Initialize the
session
And hold,session
There will be more than onetask
self.session = [NSURLSession sessionWithConfiguration:self.sessionConfiguration delegate:self delegateQueue:self.operationQueue];
Copy the code
- Setting resolution (default
JSON
), certificate (default unconditional trusthttps
), network status monitoring
self.responseSerializer = [AFJSONResponseSerializer serializer];
self.securityPolicy = [AFSecurityPolicy defaultPolicy];
self.reachabilityManager = [AFNetworkReachabilityManager sharedManager];
Copy the code
- Initialize one
NSMutableDictionary
For storing bindingstask
anddelegate(@{key:delegate]})
self.mutableTaskDelegatesKeyedByTaskIdentifier = [[NSMutableDictionary alloc] init];
Copy the code
- Initialize the thread lock
self.lock = [[NSLock alloc] init];
self.lock.name = AFURLSessionManagerLockName;
Copy the code
- Asynchronously get the current
session
All unfinishedtask
(such as initialization after coming back from the backgroundsession
, there may be previous missions)
[self.session getTasksWithCompletionHandler:^(NSArray *dataTasks, NSArray *uploadTasks, NSArray *downloadTasks) {
for (NSURLSessionDataTask *task in dataTasks) {
[self addDelegateForDataTask:task uploadProgress:nil downloadProgress:nil completionHandler:nil];
}
for (NSURLSessionUploadTask *uploadTask in uploadTasks) {
[self addDelegateForUploadTask:uploadTask progress:nil completionHandler:nil];
}
for (NSURLSessionDownloadTask *downloadTask in downloadTasks) {
[self addDelegateForDownloadTask:downloadTask progress:nil destination:nil completionHandler:nil]; }}];Copy the code
2.
To deal withurl
To giveurl
Joining together"/"
if ([[url path] length] > 0 && ![[url absoluteString] hasSuffix:@ "/"]) {
url = [url URLByAppendingPathComponent:@ ""];
}
Copy the code
3.
holdbaseURL
self.baseURL = url;
Copy the code
4.
Set serialization defaults
self.requestSerializer = [AFHTTPRequestSerializer serializer];
self.responseSerializer = [AFJSONResponseSerializer serializer];
Copy the code
Initiate a request and generate NSURLSessionDataTask
- generate
request
NSMutableURLRequest *request = [self.requestSerializer requestWithMethod:method URLString:[[NSURL URLWithString:URLString relativeToURL:self.baseURL] absoluteString] parameters:parameters error:&serializationError];
Copy the code
- generate
NSMutableURLRequest
And set the request mode
NSMutableURLRequest *mutableRequest = [[NSMutableURLRequest alloc] initWithURL:url];
mutableRequest.HTTPMethod = method;
Copy the code
- traverse
mutableObservedChangedKeyPaths
To givemutableRequest
forKVC
The assignment- in
requestSerializer
When you initialize, it’s going to bemutableObservedChangedKeyPaths
forKVO
operation
- in
for (NSString *keyPath in AFHTTPRequestSerializerObservedKeyPaths()) {
if ([self.mutableObservedChangedKeyPaths containsObject:keyPath]) {
[mutableRequest setValue:[selfvalueForKeyPath:keyPath] forKey:keyPath]; }}Copy the code
- Encode the parameters and pass them to
mutableRequest
mutableRequest = [[self requestBySerializingRequest:mutableRequest withParameters:parameters error:error] mutableCopy];
Copy the code
- Execute copy
NSMutableURLRequest *mutableRequest = [request mutableCopy];
Copy the code
- Set the request header
[self.HTTPRequestHeaders enumerateKeysAndObjectsUsingBlock:^(id field, id value, BOOL * __unused stop) {
if (![request valueForHTTPHeaderField:field]) {
[mutableRequest setValue:value forHTTPHeaderField:field];
}
}];
Copy the code
- Converts the parameter dictionary into a string to support custom parsing
1.Let's do the recursionNSArray * AFQueryStringPairsFromKeyAndValue(NSString *key, idValue) gets the AFQueryStringPair parameter array2.It then iterates through the parameter array to perform URLEncodedStringValue percent encoding on AFQueryStringPair3.The array parameters of AFQueryStringPair componentsJoinedByString:@ "&"Elements segmentation get AFQueryStringFromParameters string parametersCopy the code
NSString * AFQueryStringFromParameters(NSDictionary *parameters) {
NSMutableArray *mutablePairs = [NSMutableArray array];
for (AFQueryStringPair *pair in AFQueryStringPairsFromDictionary(parameters)) {
[mutablePairs addObject:[pair URLEncodedStringValue]];
}
return [mutablePairs componentsJoinedByString:@ "&"];
}
Copy the code
NSArray * AFQueryStringPairsFromDictionary(NSDictionary *dictionary) {
return AFQueryStringPairsFromKeyAndValue(nil, dictionary);
}
Copy the code
NSArray * AFQueryStringPairsFromKeyAndValue(NSString *key, id value) {
NSMutableArray *mutableQueryStringComponents = [NSMutableArray array];
NSSortDescriptor *sortDescriptor = [NSSortDescriptor sortDescriptorWithKey:@"description" ascending:YES selector:@selector(compare:)];
if ([value isKindOfClass:[NSDictionary class]]) {
NSDictionary *dictionary = value;
for (id nestedKey in [dictionary.allKeys sortedArrayUsingDescriptors:@[ sortDescriptor ]]) {
id nestedValue = dictionary[nestedKey];
if (nestedValue) {
[mutableQueryStringComponents addObjectsFromArray:AFQueryStringPairsFromKeyAndValue((key ? [NSString stringWithFormat:@ % @ [% @] "", key, nestedKey] : nestedKey), nestedValue)]; }}}else if ([value isKindOfClass:[NSArray class]]) {
NSArray *array = value;
for (id nestedValue in array) {
[mutableQueryStringComponents addObjectsFromArray:AFQueryStringPairsFromKeyAndValue([NSString stringWithFormat:@ % @ "[]", key], nestedValue)]; }}else if ([value isKindOfClass:[NSSet class]]) {
NSSet *set = value;
for (id obj in[set sortedArrayUsingDescriptors:@[ sortDescriptor ]]) { [mutableQueryStringComponents addObjectsFromArray:AFQueryStringPairsFromKeyAndValue(key, obj)]; }}else {
[mutableQueryStringComponents addObject:[[AFQueryStringPair alloc] initWithField:key value:value]];
}
return mutableQueryStringComponents;
}
Copy the code
- if
GET
.HEAD
.DELETE
Request to concatenate parameters tourl
Back, ifPUT
.POST
Request, check whether there are Settings firstContent-Type
If no, use the default valueapplication/x-www-form-urlencoded
And then concatenate the parameters tohttp body
In the
if ([self.HTTPMethodsEncodingParametersInURI containsObject:[[request HTTPMethod] uppercaseString]]) {
if (query && query.length > 0) {
mutableRequest.URL = [NSURL URLWithString:[[mutableRequest.URL absoluteString] stringByAppendingFormat:mutableRequest.URL.query ? @ "& % @" : @ "? % @", query]]; }}else {
if(! query) { query =@ "";
}
if(! [mutableRequest valueForHTTPHeaderField:@"Content-Type"]) {
[mutableRequest setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"];
}
[mutableRequest setHTTPBody:[query dataUsingEncoding:self.stringEncoding]];
}
Copy the code
- through
request
generatetask
1.
Created using serial queuesdtaTask
To solveiOS8
See the following bug for detailsissue 2093
__block NSURLSessionDataTask *dataTask = nil;
url_session_manager_create_task_safely(^{
dataTask = [self.session dataTaskWithRequest:request];
});
Copy the code
- to
task
Add the agent
[self addDelegateForDataTask:dataTask uploadProgress:uploadProgressBlock downloadProgress:downloadProgressBlock completionHandler:completionHandler];
Copy the code
- In order to
taskId
forkey
willdelegate
depositmutableTaskDelegatesKeyedByTaskIdentifier
, eachtask
They have their owndelegate
manager
>session
>task
<>delegate
>manager
(weak
To prevent circular references.manager
holdtask
.task
anddelegate
It’s bound. It’s equivalent tomanager
Is to havedelegate
the- with
KVO
Listening to theAFURLSessionManagerTaskDelegate
thedownloadProgress
anduploadProgress
- with
KVO
Listening to theTask
theprogress
, will be monitoredcompletedUnitCount
andtotalUnitCount
Assigned todownloadProgress
anduploadProgress
- Listen to the
downloadProgress
anduploadProgress
Change, callThe AFURLSessionManagerTaskDelegate downloadProgressBlock
anduploadProgressBlock
The callback
resume()
task
theresume()
Be replaced byaf_resume()
- (void)af_resume {
NSAssert([self respondsToSelector:@selector(state)], @"Does not respond to state");
NSURLSessionTaskState state = [self state];
[self af_resume];
if(state ! =NSURLSessionTaskStateRunning) {[[NSNotificationCenter defaultCenter] postNotificationName:AFNSURLSessionTaskDidResumeNotification object:self]; }}Copy the code
- when
task
Notifies when the status changesmanager
- (void)addNotificationObserverForTask:(NSURLSessionTask *)task {
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(taskDidResume:) name:AFNSURLSessionTaskDidResumeNotification object:task];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(taskDidSuspend:) name:AFNSURLSessionTaskDidSuspendNotification object:task];
}
Copy the code
manager
releasetask
Status change broadcast
- (void)taskDidResume:(NSNotification *)notification {
NSURLSessionTask *task = notification.object;
if ([task respondsToSelector:@selector(taskDescription)]) {
if ([task.taskDescription isEqualToString:self.taskDescriptionForSessionTasks]) {
dispatch_async(dispatch_get_main_queue(), ^{
[[NSNotificationCenterdefaultCenter] postNotificationName:AFNetworkingTaskDidResumeNotification object:task]; }); }}}Copy the code