淘汰掉了ASIHTTPRequest和MKNetworkit,AFNetworking完美胜出
起初
新建一个工程HelloWorld,你想在这个工程中通过pod来集成使用第三方库AFNetworking。
使用终端进入工程根目录,然后编辑Podfile:
vim Podfile
【这里你也许会遇到一个问题终端左下角会提示E353:Nothing in register,不要慌,这并不是什么问题,而是自己操作错误,这时候只要按【i】或者【a】进入vi的插入模式就可以编辑了】
这里普及一下vi的工作模式:
1、命令行模式:用光标在字符之间来回移动,进行删除、复制、移动字符等操作,按【i】或者【a】进入插入模式,按【:】(冒号)进入末行模式;
2、插入模式:输入你要编辑的内容,按【esc】返回命令行模式,按【:】(冒号)进入末行模式;
3、末行模式:保存文件或者退出vi,输入【wq】存盘并退出vi,输入【q!】不保存强制退出vi,输入【w:filename】将文件保存为制定的文件名。
结束上述Podfile编辑后,在终端运行
pod install
【 相关命令`pod repo update` or with `pod install --repo-update`】
了解
AFNetworking框架由会话(NSURLSeeion)、网络监听模块(Reachability)、网络安全模块(Security)、请求序列化(Serialization)、响应序列化(Serialization)和UIKit集成模块(UIKit)构成
如图:
库中最核心的类是AFURLSessionManager,使用频率最高的是其子类AFHTTPSessionManager,在该类中包含了负责请求序列化的AFURLRequestSerialization和响应序列化AFURLResponseSerializer,AFURLSessionManager还提供了会话模块NSURLSession、保证网络安全的AFSecurityPolicy、网络监听的AFNetworkReachabilityManager。
如图:
使用
首先在头部导入#import <AFNetworking/AFNetworking.h>
写个get请求
// 实现一个get请求
-(void)makeGetRequest{
AFHTTPSessionManager *sessionManager = [AFHTTPSessionManager manager];
NSDictionary *headerDic = [NSDictionary dictionaryWithObjectsAndKeys:@"application/json",@"Content-Type", nil];
[sessionManager GET:@"http://wna.test.com/app" parameters:nil headers:headerDic progress:^(NSProgress * _Nonnull downloadProgress) {
} success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
NSLog(@"接口请求成功-- %@",responseObject);
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
NSLog(@"接口请求失败-- %@",error);
}];
}
写个post请求
// 实现一个post请求
- (void)makePostRequest{
AFHTTPSessionManager *sessionManager = [AFHTTPSessionManager manager];
NSDictionary *headerDic = @{
@"nbp-app-name":@"dog",
@"Content-Type":@"application/json",
};
NSDictionary *parames = @{
@"methodType":@"GET",
@"moduleName":@"app-product",
@"url":@"product/new_product_list",
};
[sessionManager POST:@"http://wna.test.com/app" parameters:parames headers:headerDic progress:^(NSProgress * _Nonnull uploadProgress) {
} success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
NSData *tempDisplay = [NSJSONSerialization dataWithJSONObject:responseObject options:NSJSONWritingPrettyPrinted error:nil];
NSString *result = [[NSString alloc] initWithData:tempDisplay encoding:NSUTF8StringEncoding];
NSLog(@"接口请求成功-- %@",result);
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
NSLog(@"接口请求失败-- %@",error);
}];
}
方法的逐级调用
get方法的源码:
- (NSURLSessionDataTask *)GET:(NSString *)URLString
parameters:(nullable id)parameters
headers:(nullable NSDictionary <NSString *, NSString *> *)headers
progress:(nullable void (^)(NSProgress * _Nonnull))downloadProgress
success:(nullable void (^)(NSURLSessionDataTask * _Nonnull, id _Nullable))success
failure:(nullable void (^)(NSURLSessionDataTask * _Nullable, NSError * _Nonnull))failure
{
NSURLSessionDataTask *dataTask = [self dataTaskWithHTTPMethod:@"GET"
URLString:URLString
parameters:parameters
headers:headers
uploadProgress:nil
downloadProgress:downloadProgress
success:success
failure:failure];
[dataTask resume];
return dataTask;
}
入参有请求的URL,参数,请求头,进度Block,成功Block和失败Block。在这个方法中初始化了一个NSURLSessionDataTask的类,NSURLSessionDataTask继承自NSURLSessionTask,NSURLSessionDataTask不提供NSURLSessionTask的任何附加功能,他的存在是为了区别于上载NSURLSessionUploadTask和下载NSURLSessionDownloadTask。
继续往下看
- (NSURLSessionDataTask *)dataTaskWithHTTPMethod:(NSString *)method
URLString:(NSString *)URLString
parameters:(nullable id)parameters
headers:(nullable NSDictionary <NSString *, NSString *> *)headers
uploadProgress:(nullable void (^)(NSProgress *uploadProgress)) uploadProgress
downloadProgress:(nullable void (^)(NSProgress *downloadProgress)) downloadProgress
success:(nullable void (^)(NSURLSessionDataTask *task, id _Nullable responseObject))success
failure:(nullable void (^)(NSURLSessionDataTask * _Nullable task, NSError *error))failure
{
NSError *serializationError = nil;
NSMutableURLRequest *request = [self.requestSerializer requestWithMethod:method URLString:[[NSURL URLWithString:URLString relativeToURL:self.baseURL] absoluteString] parameters:parameters error:&serializationError];
for (NSString *headerField in headers.keyEnumerator) {
[request setValue:headers[headerField] forHTTPHeaderField:headerField];
}
if (serializationError) {
if (failure) {
dispatch_async(self.completionQueue ?: dispatch_get_main_queue(), ^{
failure(nil, serializationError);
});
}
return nil;
}
__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对象
- 实例化NSURLSessionDataTask对象,并返回
在这个方法里是通过一个实现了AFURLRequestSerialization协议的请求序列化实例对象AFHTTPRequestSerializer来调用其实例方法得到一个NSMutableURLRequest对象。
- (nullable NSMutableURLRequest *)requestWithMethod:(NSString *)method
URLString:(NSString *)URLString
parameters:(nullable id)parameters
error:(NSError * _Nullable __autoreleasing *)error;
我们看下该方法的实现
- (NSMutableURLRequest *)requestWithMethod:(NSString *)method
URLString:(NSString *)URLString
parameters:(id)parameters
error:(NSError *__autoreleasing *)error
{
NSParameterAssert(method);
NSParameterAssert(URLString);
// 初识化URL
NSURL *url = [NSURL URLWithString:URLString];
NSParameterAssert(url);
// 初始化Request
NSMutableURLRequest *mutableRequest = [[NSMutableURLRequest alloc] initWithURL:url];
// 设置请求方式
mutableRequest.HTTPMethod = method;
// 为某些属性赋值【allowsCellularAccess,cachePolicy,HTTPShouldHandleCookies,HTTPShouldUsePipelining,networkServiceType,timeoutInterval】
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;
}
在实现的协议中,真正的完成了一条完整的请求,请求地址,请求头,请求体
- (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;
}
}
}
// 如果是GET,HEAD,DELETE 走这边
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 {
// POST、PUT走这里
// #2864: an empty string is a valid x-www-form-urlencoded payload
if (!query) {
query = @"";
}
// 如果没有设置Content-Type,此处默认设置成application/x-www-form-urlencoded
if (![mutableRequest valueForHTTPHeaderField:@"Content-Type"]) {
[mutableRequest setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"];
}
// 配置请求体
[mutableRequest setHTTPBody:[query dataUsingEncoding:self.stringEncoding]];
}
return mutableRequest;
}
上面这块是NSMutableURLRequest的整个过程,下面看下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 {
NSURLSessionDataTask *dataTask = [self.session dataTaskWithRequest:request];
[self addDelegateForDataTask:dataTask uploadProgress:uploadProgressBlock downloadProgress:downloadProgressBlock completionHandler:completionHandler];
return dataTask;
}
该方法中通过NSURLSession创建了一个NSURLSessionDataTask对象,并给dataTask添加代理
在session的初始化中添加了安全锁,保证了线程的安全。
- (NSURLSession *)session {
@synchronized (self) {
if (!_session) {
_session = [NSURLSession sessionWithConfiguration:self.sessionConfiguration delegate:self delegateQueue:self.operationQueue];
}
}
return _session;
}
- (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 *delegate = [[AFURLSessionManagerTaskDelegate alloc] initWithTask:dataTask];
delegate.manager = self;
delegate.completionHandler = completionHandler;
dataTask.taskDescription = self.taskDescriptionForSessionTasks;
[self setDelegate:delegate forTask:dataTask];
delegate.uploadProgressBlock = uploadProgressBlock;
delegate.downloadProgressBlock = downloadProgressBlock;
}
上面就是一条完整的调用流程,回到最初的地方[dataTask resume];开始网络请求
AFN使用技巧
- 创建一个工具类,继承自AFNetwork的请求管理者
- 工具类中提供一个单例方法和一个基本的请求路径,提供对GET和POST的请求封装
- 发送请求使用自己封装的工具类
- 方便修改,如果修改了底层的依赖框架,只用修改工具类就可以了
相关面试问题:
AFURLSessionManager主要负责哪些功能?
- 创建和管理NSURLSession、NSURLSessionTask
- 实现NSURLSessionDelegate等协议的代理方法
- 引入AFSecurityPolicy保证请求的网络安全(证书的校验。公钥的验证等)
- 引入AFNetworkReachabilityManager监听网络状态