之前有总结iOS原生网络的使用,今天来总结一下基于NSURLSession封装的优秀开源框架AFNetWorking。
不知道有没人和我一样,接触网络是从AFNetWorking开始的,那个时候就觉得AFNetWorking是相当的优秀,极大的降低了iOS开发工程师处理网络请求的难度,让iOS开发变成一件愉快的事情,当然现在也是这么觉得,因为自己还没有接触文件的上传下载,所以这篇文章只说HTTP的两个请求:Get和Post。
1.AFHTTPSessionManager
AFHTTPSessionManager请求管理者,是为了便利使用HTTP请求,当一个baseURL提供时,用相对路径构造GET/POST等便利的方法创建请求,扒出部分源码声明如下:
@interfaceAFHTTPSessionManager:AFURLSessionManager
// 当baseURL提供时,用相对路径构造GET/POST等便利方法来创建请求
@property (readonly, nonatomic, strong, nullable) NSURL *baseURL;
// 请求数据序列化
@property (nonatomic, strong) AFHTTPRequestSerializer <AFURLRequestSerialization> * requestSerializer;
// 响应数据序列化
@property (nonatomic, strong) AFHTTPResponseSerializer <AFURLResponseSerialization> * responseSerializer;
// 创建会话使用的安全策略
@property (nonatomic, strong) AFSecurityPolicy *securityPolicy;
// 创建并返回一个‘AFHTTPSessionManager’对象
+ (instancetype)manager;
// 使用指定的基本URL初始化对象
- (instancetype)initWithBaseURL:(nullable NSURL *)url;
//Get请求
- (NSURLSessionDataTask *)GET:(NSString *)URLString
parameters:(id)parameters
success:(void(^)(NSURLSessionDataTask*task,idresponseObject))success
failure:(void(^)(NSURLSessionDataTask*task,NSError*error))failure
{
return[selfGET:URLStringparameters:parametersprogress:nilsuccess:successfailure:failure];
}
//Post请求
- (NSURLSessionDataTask *)POST:(NSString *)URLString
parameters:(id)parameters
success:(void(^)(NSURLSessionDataTask*task,idresponseObject))success
failure:(void(^)(NSURLSessionDataTask*task,NSError*error))failure
{
return[selfPOST:URLStringparameters:parametersprogress:nilsuccess:successfailure:failure];
}
@end
处理Get请求
AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
NSString*urlString = @"http://localhost:3030/userinfo";
NSDictionary *parameters=@{@"name":@"zyp",@"pwd":@"666"};
[manager GET:urlString parameters:parameters progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
NSLog(@"请求成功");
}failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
NSLog(@"请求失败");
}];
处理Post请求
AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
NSString*urlString = @"http://localhost:3030/userinfo";
NSDictionary *parameters=@{@"name":@"zhaoyipei",@"pwd":@"yang"};
[manager POST:urlString parameters:parameters progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
NSLog(@"请求成功");
}failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
NSLog(@"请求失败");
}];
AFNetWorking内存泄露
AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];一般来说,我们会认为,这个manager是个单例,但是我们来看一下源码:
+ (instancetype)manager {
return [[[self class] alloc] initWithBaseURL:nil];
}
然后发现被骗了,它其实是每次都实例化一个AFHTTPSessionManager对象,所以必要的时候需要自己封装一下。
简单实现NSURLSession封装
.h文件
//请求序列化格式
typedef enum {
HTTPRequestSerializationURLEncoded =0,
HTTPRequestSerializationJSON
} HTTPRequestSerializationType;
@interface HTTPRequestManager : NSObject
+ (instancetype)manager;
@property (nonatomic, assign) HTTPRequestSerializationType serializationType;
- (void)GET:(NSString *)URL
parameters:(NSDictionary *)parameters
success:(void(^)(idobject))success
failure:(void(^)(NSError*error))failure;
- (void)POST:(NSString *)URL
parameters:(NSDictionary *)parameters
success:(void(^)(idobject))success
failure:(void(^)(NSError*error))failure;
@end
.m文件
#import "HTTPRequestManager.h"
@implementation HTTPRequestManager
+ (instancetype)manager
{
return [[self alloc] init];
}
- (void)GET:(NSString *)URL
parameters:(NSDictionary *)parameters
success:(void (^)(id _Nonnull))success
failure:(void (^)(NSError * _Nonnull))failure
{
if (URL.length == 0) {
if (failure) {
failure([NSError errorWithDomain:@"123" code:-1 userInfo:nil]);
}
return;
}
//Get请求的内容是拼接在URL后面的,所以要通过NSURLComponents对parameters进行处理
NSURLComponents *URLcomponents = [NSURLComponents componentsWithString:URL];
NSArray *old = URLcomponents.queryItems;
NSMutableArray *array = old ? [old mutableCopy] : [NSMutableArray new];
[parameters enumerateKeysAndObjectsUsingBlock:^(id _Nonnull key, id _Nonnull obj, BOOL * _Nonnull stop) {
NSURLQueryItem *queryItem = [NSURLQueryItem queryItemWithName:key value:obj];
[array addObject:queryItem];
}];
URLcomponents.queryItems = array;
// 1.创建请求会话
NSURLSession *session = [NSURLSession sharedSession];
// 2.创建请求
NSURLRequest *request = [NSURLRequest requestWithURL:URLcomponents.URL];
// 3.创建请求任务
NSURLSessionDataTask *task = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
if (error) {
if (failure) {
failure(error);
}
return;
}
NSDictionary *json = [NSJSONSerialization JSONObjectWithData:data options:0 error:NULL];
if (success) {
success(json);
}
}];
// 4.开始任务
[task resume];
}
- (void)POST:(NSString *)URL
parameters:(NSDictionary *)parameters
success:(void (^)(id _Nonnull))success
failure:(void (^)(NSError * _Nonnull))failure
{
NSURL *requestURL = [NSURL URLWithString:URL];
NSMutableURLRequest *mRequest = [NSMutableURLRequest requestWithURL:requestURL];
mRequest.HTTPMethod = @"POST";
//根据MIME类型,对parameters进行处理
if (parameters.count) {
if (self.serializationType == HTTPRequestSerializationJSON) {
[mRequest setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
mRequest.HTTPBody = [NSJSONSerialization dataWithJSONObject:parameters options:kNilOptions error:NULL];
} else {
[mRequest setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"];
NSMutableArray *array = [[NSMutableArray alloc]initWithCapacity:parameters.count];
[parameters enumerateKeysAndObjectsUsingBlock:^(id _Nonnull key, id _Nonnull obj, BOOL * _Nonnull stop) {
[array addObject:[NSString stringWithFormat:@"%@=%@", key, obj]];
}];
NSString *urlEncode = [array componentsJoinedByString:@"&"];
mRequest.HTTPBody = [urlEncode dataUsingEncoding:NSUTF8StringEncoding];
}
}
NSURLSession *session = [NSURLSession sharedSession];
NSURLSessionDataTask *task = [session dataTaskWithRequest:mRequest completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
if (error) {
if (failure) {
failure(error);
}
return;
}
NSDictionary *json = [NSJSONSerialization JSONObjectWithData:data options:0 error:NULL];
if (success) {
success(json);
}
}];
// 4.开始任务
[task resume];
}
@end
然后呢,就会发现这个看起来太臃肿,并且很明显,在Get请求和Post请求都涉及到NSURLSession和NSURLSessionDataTask,只是在NSURLRequest的处理上有差异,所以我们可以进一步将NSURLSessionDataTask进行封装,完了之后结果如下:
- (void)GET:(NSString *)URL
parameters:(NSDictionary *)parameters
success:(void (^)(id _Nonnull))success
failure:(void (^)(NSError * _Nonnull))failure
{
if (URL.length == 0) {
if (failure) {
failure([NSError errorWithDomain:@"123" code:-1 userInfo:nil]);
}
return;
}
NSURLComponents *URLcomponents = [NSURLComponents componentsWithString:URL];
NSArray *old = URLcomponents.queryItems;
NSMutableArray *array = old ? [old mutableCopy] : [NSMutableArray new];
[parameters enumerateKeysAndObjectsUsingBlock:^(id _Nonnull key, id _Nonnull obj, BOOL * _Nonnull stop) {
NSURLQueryItem *queryItem = [NSURLQueryItem queryItemWithName:key value:obj];
[array addObject:queryItem];
}];
URLcomponents.queryItems = array;
// 2.创建请求
NSURLRequest *request = [NSURLRequest requestWithURL:URLcomponents.URL];
[self request:request success:success failure:failure];
}
- (void)POST:(NSString *)URL
parameters:(NSDictionary *)parameters
success:(void (^)(id _Nonnull))success
failure:(void (^)(NSError * _Nonnull))failure
{
NSURL *requestURL = [NSURL URLWithString:URL];
NSMutableURLRequest *mRequest = [NSMutableURLRequest requestWithURL:requestURL];
mRequest.HTTPMethod = @"POST";
if (parameters.count) {
if (self.serializationType == HTTPRequestSerializationJSON) {
[mRequest setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
mRequest.HTTPBody = [NSJSONSerialization dataWithJSONObject:parameters options:kNilOptions error:NULL];
} else {
[mRequest setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"];
NSMutableArray *array = [[NSMutableArray alloc]initWithCapacity:parameters.count];
[parameters enumerateKeysAndObjectsUsingBlock:^(id _Nonnull key, id _Nonnull obj, BOOL * _Nonnull stop) {
[array addObject:[NSString stringWithFormat:@"%@=%@", key, obj]];
}];
NSString *urlEncode = [array componentsJoinedByString:@"&"];
mRequest.HTTPBody = [urlEncode dataUsingEncoding:NSUTF8StringEncoding];
}
}
[self request:mRequest success:success failure:failure];
}
- (void)request:(NSURLRequest *)request
success:(void (^)(id _Nonnull))success
failure:(void (^)(NSError * _Nonnull))failure {
NSURLSession *session = [NSURLSession sharedSession];
NSURLSessionDataTask *task = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
if (error) {
if (failure) {
failure(error);
}
return;
}
NSDictionary *json = [NSJSONSerialization JSONObjectWithData:data options:0 error:NULL];
if (success) {
success(json);
}
}];
// 4.开始任务
[task resume];
}