AFNetworking
AFNetworking 是一个网络请求封装框架,使用简单,功能强大;
在AFNetworking 3.x版本 通过封装NSURLSession,通过简单的API是我们可以简单快捷实用。
AFNetworking模块
- NSURLSession 封装NSURLSession的模块
- Reachability 网络状态
- Security 网络安全配置HTTPS
- Serialization 序列化 包括 json
- UIKit 一些关于UIKit的Category,在UIKit中快速的使用NSURLSession模块
NSURLSession 系统请求
NSURL *requestURL = [NSURL URLWithString:[NSString stringWithFormat:@"urlStr"]];
NSURLRequest *request = [NSURLRequest requestWithURL:requestURL];
NSURLSession *session = [NSURLSession sharedSession];
NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
}];
[dataTask resume];
这只是基本的请求,没有进行其他配置。
系统源生的请求方式,相比APNetworking使用繁琐,需要自己进行序列化和返回状态判断等。
AFNetworking 基本使用
AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
[manager POST:@"urlStr" parameters:nil progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
}];
使用就是这么简单那么,AFNetworking中间做了什么操作呢?
任务的创建
[AFHTTPSessionManager manager]
+ (instancetype)manager {
return [[[self class] alloc] initWithBaseURL:nil];
}
- (instancetype)initWithBaseURL:(NSURL *)url {
return [self initWithBaseURL:url sessionConfiguration:nil];
}
- (instancetype)initWithSessionConfiguration:(NSURLSessionConfiguration *)configuration {
return [self initWithBaseURL:nil sessionConfiguration:configuration];
}
- (instancetype)initWithBaseURL:(NSURL *)url
sessionConfiguration:(NSURLSessionConfiguration *)configuration
{
//[super initWithSessionConfiguration:configuration]; 对应下面的方法
self = [super initWithSessionConfiguration:configuration];
if (!self) {
return nil;
}
// Ensure terminal slash for baseURL path, so that NSURL +URLWithString:relativeToURL: works as expected
if ([[url path] length] > 0 && ![[url absoluteString] hasSuffix:@"/"]) {
url = [url URLByAppendingPathComponent:@""];
}
self.baseURL = url;
self.requestSerializer = [AFHTTPRequestSerializer serializer];
self.responseSerializer = [AFJSONResponseSerializer serializer];
return self;
}
//AFUrlSessionManager 中的操作
- (instancetype)initWithSessionConfiguration:(NSURLSessionConfiguration *)configuration {
self = [super init];
if (!self) {
return nil;
}
if (!configuration) {
configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
}
self.sessionConfiguration = configuration;
//操作队列
self.operationQueue = [[NSOperationQueue alloc] init];
//串行操作队列
self.operationQueue.maxConcurrentOperationCount = 1;
//设置session的delegate
self.session = [NSURLSession sessionWithConfiguration:self.sessionConfiguration delegate:self delegateQueue:self.operationQueue];
//响应数据序列化
self.responseSerializer = [AFJSONResponseSerializer serializer];
//身份认证
self.securityPolicy = [AFSecurityPolicy defaultPolicy];
#if !TARGET_OS_WATCH // 非iWatch
self.reachabilityManager = [AFNetworkReachabilityManager sharedManager];
#endif
//根据 task.taskIdentifier 对应的 AFURLSessionManagerTaskDelegate对象的字典
self.mutableTaskDelegatesKeyedByTaskIdentifier = [[NSMutableDictionary alloc] init];
self.lock = [[NSLock alloc] init];
self.lock.name = AFURLSessionManagerLockName;
//处理未完成的task
[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];
}
}];
return self;
}
简化
[AFHTTPSessionManager manager]
[AFHTTPSessionManager initWithBaseURL:]
[AFHTTPSessionManager initWithBaseURL: sessionConfiguration:]
[AFUrlSessionManager initWithSessionConfiguration:]
[NSOperationQueue alloc] init] //请求操作队列
[NSURLSession sessionWithConfiguration: delegate: delegateQueue:]
[AFJSONResponseSerializer serializer] //响应序列化
[AFSecurityPolicy defaultPolicy] //安全机制
[AFNetworkReachabilityManager sharedManager] //网络状态 TARGET_OS_WATCH 没有此操作
[AFHTTPRequestSerializer serializer] //请求序列化
[AFJSONResponseSerializer serializer] //响应序列化
[AFHTTPSessionManager POST: parameters: progress: success: failure:]
请求调用简化:
[AFHTTPSessionManager POST: parameters: progress: success: failure:]
[AFHTTPSessionManager dataTaskWithHTTPMethod: URLString:URLString parameters: uploadProgress: downloadProgress: success: failure:]
[NSURL URLWithString:]
[[NSMutableURLRequest alloc] initWithURL:]
[[AFUrlRequestSerialization requestBySerializingRequest: withParameters: error:]
[AFURLSessionManager dataTaskWithRequest: uploadProgress: downloadProgress: completionHandler:]
[AFURLSessionManager addDelegateForDataTask: uploadProgress: downloadProgress: completionHandler:]
主要是用的方法介绍:
- (NSURLSessionDataTask *)POST:(NSString *)URLString
parameters:(id)parameters
progress:(void (^)(NSProgress * _Nonnull))uploadProgress
success:(void (^)(NSURLSessionDataTask * _Nonnull, id _Nullable))success
failure:(void (^)(NSURLSessionDataTask * _Nullable, NSError * _Nonnull))failure
{
//创建task
NSURLSessionDataTask *dataTask = [self dataTaskWithHTTPMethod:@"POST" URLString:URLString parameters:parameters uploadProgress:uploadProgress downloadProgress:nil success:success failure:failure];
//启动task
[dataTask resume];
return dataTask;
}
创建一个NSURLSessionDataTask 并且开启请求任务。
- (NSURLSessionDataTask *)dataTaskWithHTTPMethod:(NSString *)method
URLString:(NSString *)URLString
parameters:(id)parameters
uploadProgress:(nullable void (^)(NSProgress *uploadProgress)) uploadProgress
downloadProgress:(nullable void (^)(NSProgress *downloadProgress)) downloadProgress
success:(void (^)(NSURLSessionDataTask *, id))success
failure:(void (^)(NSURLSessionDataTask *, NSError *))failure
{
NSError *serializationError = nil;
//对 request 和 parameters 进行序列化
NSMutableURLRequest *request = [self.requestSerializer requestWithMethod:method URLString:[[NSURL URLWithString:URLString relativeToURL:self.baseURL] absoluteString] parameters:parameters error:&serializationError];
if (serializationError) {
if (failure) {
dispatch_async(self.completionQueue ?: dispatch_get_main_queue(), ^{
failure(nil, serializationError);
});
}
return nil;
}
//创建task
__block NSURLSessionDataTask *dataTask = nil;
dataTask = [self dataTaskWithRequest:request
uploadProgress:uploadProgress
downloadProgress:downloadProgress
completionHandler:^(NSURLResponse * __unused response, id responseObject, NSError *error) {
if (error) {
if (failure) {
failure(dataTask, error);
}
} else {
if (success) {
success(dataTask, responseObject);
}
}
}];
return dataTask;
}
第一部分是构造 NSMutableURLRequest
- (NSMutableURLRequest *)requestWithMethod:(NSString *)method
URLString:(NSString *)URLString
parameters:(id)parameters
error:(NSError *__autoreleasing *)error
{
NSParameterAssert(method);
NSParameterAssert(URLString);
NSURL *url = [NSURL URLWithString:URLString];
NSParameterAssert(url);
NSMutableURLRequest *mutableRequest = [[NSMutableURLRequest alloc] initWithURL:url];
mutableRequest.HTTPMethod = method;
for (NSString *keyPath in AFHTTPRequestSerializerObservedKeyPaths()) {
if ([self.mutableObservedChangedKeyPaths containsObject:keyPath]) {
[mutableRequest setValue:[self valueForKeyPath:keyPath] forKey:keyPath];
}
}
mutableRequest = [[self requestBySerializingRequest:mutableRequest withParameters:parameters error:error] mutableCopy];
return mutableRequest;
}
self.mutableObservedChangedKeyPaths 中的内容是通过设置NSURLRequest以下的属性
//网络请求是否使用蜂窝移动网络
@property BOOL allowsCellularAccess API_AVAILABLE(macos(10.8), ios(6.0), watchos(2.0), tvos(9.0));
//缓存策略
@property NSURLRequestCachePolicy cachePolicy;
//cookie cookie是否添加到NSURLRequest
@property BOOL HTTPShouldHandleCookies;
//多管道 可以理解为请求是否等到上一个请求响应 在发送下一个请求 相当于同步 yes 相当于异步。
@property BOOL HTTPShouldUsePipelining API_AVAILABLE(macos(10.7), ios(4.0), watchos(2.0), tvos(9.0));
//请求数据类型
@property NSURLRequestNetworkServiceType networkServiceType API_AVAILABLE(macos(10.7), ios(4.0), watchos(2.0), tvos(9.0));
//请求超时时间
@property NSTimeInterval timeoutInterval;
只有设置了以上属性才会把属性添加到self.mutableObservedChangedKeyPaths中 通过观察者实现的
- (NSURLRequest *)requestBySerializingRequest:(NSURLRequest *)request
withParameters:(id)parameters
error:(NSError *__autoreleasing *)error
{
NSParameterAssert(request);
NSMutableURLRequest *mutableRequest = [request mutableCopy];
[self.HTTPRequestHeaders enumerateKeysAndObjectsUsingBlock:^(id field, id value, BOOL * __unused stop) {
if (![request valueForHTTPHeaderField:field]) {
[mutableRequest setValue:value forHTTPHeaderField:field];
}
}];
NSString *query = nil;
if (parameters) {
if (self.queryStringSerialization) {
NSError *serializationError;
query = self.queryStringSerialization(request, parameters, &serializationError);
if (serializationError) {
if (error) {
*error = serializationError;
}
return nil;
}
} else {
switch (self.queryStringSerializationStyle) {
case AFHTTPRequestQueryStringDefaultStyle:
query = AFQueryStringFromParameters(parameters);
break;
}
}
}
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 {
// #2864: an empty string is a valid x-www-form-urlencoded payload
if (!query) {
query = @"";
}
if (![mutableRequest valueForHTTPHeaderField:@"Content-Type"]) {
//表单上传
[mutableRequest setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"];
}
[mutableRequest setHTTPBody:[query dataUsingEncoding:self.stringEncoding]];
}
return mutableRequest;
}
- 以设置 HTTPHeader
- 将parameters 转换成 String 例如 @{@"name":@"123", @"phone":@"456"} => name=123&phone=456
- 处理参数 如果GET/HEAD/DELETE 参数拼接到urlStr后面 GET放到HTTPBODY中
第二部分是构造 NSURLSessionDataTask
- (NSURLSessionDataTask *)dataTaskWithRequest:(NSURLRequest *)request
uploadProgress:(nullable void (^)(NSProgress *uploadProgress)) uploadProgressBlock
downloadProgress:(nullable void (^)(NSProgress *downloadProgress)) downloadProgressBlock
completionHandler:(nullable void (^)(NSURLResponse *response, id _Nullable responseObject, NSError * _Nullable error))completionHandler {
__block NSURLSessionDataTask *dataTask = nil;
url_session_manager_create_task_safely(^{
dataTask = [self.session dataTaskWithRequest:request];
});
[self addDelegateForDataTask:dataTask uploadProgress:uploadProgressBlock downloadProgress:downloadProgressBlock completionHandler:completionHandler];
return dataTask;
}
- (void)addDelegateForDataTask:(NSURLSessionDataTask *)dataTask
uploadProgress:(nullable void (^)(NSProgress *uploadProgress)) uploadProgressBlock
downloadProgress:(nullable void (^)(NSProgress *downloadProgress)) downloadProgressBlock
completionHandler:(void (^)(NSURLResponse *response, id responseObject, NSError *error))completionHandler
{
//创建 AFURLSessionManagerTaskDelegate对象
AFURLSessionManagerTaskDelegate *delegate = [[AFURLSessionManagerTaskDelegate alloc] initWithTask:dataTask];
delegate.manager = self;
//delegate 中保存 completionHandler 完成block
delegate.completionHandler = completionHandler;
dataTask.taskDescription = self.taskDescriptionForSessionTasks;
[self setDelegate:delegate forTask:dataTask];
//delegate 中保存 uploadProgressBlock 上传进度block
delegate.uploadProgressBlock = uploadProgressBlock;
//delegate 中保存 uploadProgressBlock 下载进度block
delegate.downloadProgressBlock = downloadProgressBlock;
}
- (void)setDelegate:(AFURLSessionManagerTaskDelegate *)delegate
forTask:(NSURLSessionTask *)task
{
NSParameterAssert(task);
NSParameterAssert(delegate);
[self.lock lock];
//task.taskIdentifier 唯一标识
//把 delegate 保存到 self.mutableTaskDelegatesKeyedByTaskIdentifier字典中
self.mutableTaskDelegatesKeyedByTaskIdentifier[@(task.taskIdentifier)] = delegate;
//添加任务开始和被挂起的通知
[self addNotificationObserverForTask:task];
[self.lock unlock];
}
以上是创建任务的过程
任务的调用过程
在 AFHTTPSessionManager *manager =[AFHTTPSessionManager manager]构造 中我们设置session的delegate为manager。
AFHTTPSessionManager继承AFURLSessionManager, 中实现的NSURLSession的相关代理,如下
@interface AFURLSessionManager : NSObject <NSURLSessionDelegate, NSURLSessionTaskDelegate, NSURLSessionDataDelegate, NSURLSessionDownloadDelegate, NSSecureCoding, NSCopying>
这里面重点介绍
NSURLSessionTaskDelegate
//请求重定向功能 通过处理completionHandler来确定是否阻止重定向如果 completionHandler(request) 不阻止 completionHandler(nil)阻止改重定向
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task
willPerformHTTPRedirection:(NSHTTPURLResponse *)response
newRequest:(NSURLRequest *)request
completionHandler:(void (^)(NSURLRequest * _Nullable))completionHandler;
//身份验证处理
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task
didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge
completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential * _Nullable credential))completionHandler;
//可以重新发送新的 bodyStream 一般身份验证失败使用
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task
needNewBodyStream:(void (^)(NSInputStream * _Nullable bodyStream))completionHandler;
//上传进度
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task
didSendBodyData:(int64_t)bytesSent
totalBytesSent:(int64_t)totalBytesSent
totalBytesExpectedToSend:(int64_t)totalBytesExpectedToSend;
//任务收集完完整的统计信息后发送
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didFinishCollectingMetrics:(NSURLSessionTaskMetrics *)metrics API_AVAILABLE(macosx(10.12), ios(10.0), watchos(3.0), tvos(10.0));
//request结束(包括请求完成和任务失败) error为nil 表示任务完成
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task
didCompleteWithError:(nullable NSError *)error;
在创建NSURLSessionDataTask会保存 [AFURLSessionManager dataTaskWithRequest: uploadProgress: downloadProgress: completionHandler:]中的 uploadProgress,downloadProgress,completionHandler,当[task reusem]是 session的delegate就会调用 session的相关代理 然后通过 self.mutableTaskDelegatesKeyedByTaskIdentifier[@(task.taskIdentifier)] 当session 的相关delegate方法调用时,会调用AFURLSessionManagerTaskDelegate对象中的对应方法, 然后在回调响应的block。