之前有總結(jié)iOS原生網(wǎng)絡的使用,今天來總結(jié)一下基于NSURLSession封裝的優(yōu)秀開源框架AFNetWorking烙丛。
不知道有沒人和我一樣跳纳,接觸網(wǎng)絡是從AFNetWorking開始的疟暖,那個時候就覺得AFNetWorking是相當?shù)膬?yōu)秀紊搪,極大的降低了iOS開發(fā)工程師處理網(wǎng)絡請求的難度蜜葱,讓iOS開發(fā)變成一件愉快的事情,當然現(xiàn)在也是這么覺得耀石,因為自己還沒有接觸文件的上傳下載牵囤,所以這篇文章只說HTTP的兩個請求:Get和Post。
1.AFHTTPSessionManager
AFHTTPSessionManager請求管理者滞伟,是為了便利使用HTTP請求揭鳞,當一個baseURL提供時,用相對路徑構(gòu)造GET/POST等便利的方法創(chuàng)建請求梆奈,扒出部分源碼聲明如下:
@interfaceAFHTTPSessionManager:AFURLSessionManager
// 當baseURL提供時汹桦,用相對路徑構(gòu)造GET/POST等便利方法來創(chuàng)建請求
@property (readonly, nonatomic, strong, nullable) NSURL *baseURL;
// 請求數(shù)據(jù)序列化
@property (nonatomic, strong) AFHTTPRequestSerializer <AFURLRequestSerialization> * requestSerializer;
// 響應數(shù)據(jù)序列化
@property (nonatomic, strong) AFHTTPResponseSerializer <AFURLResponseSerialization> * responseSerializer;
// 創(chuàng)建會話使用的安全策略
@property (nonatomic, strong) AFSecurityPolicy *securityPolicy;
// 創(chuàng)建并返回一個‘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內(nèi)存泄露
AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];一般來說鉴裹,我們會認為,這個manager是個單例钥弯,但是我們來看一下源碼:
+ (instancetype)manager {
return [[[self class] alloc] initWithBaseURL:nil];
}
然后發(fā)現(xiàn)被騙了径荔,它其實是每次都實例化一個AFHTTPSessionManager對象,所以必要的時候需要自己封裝一下脆霎。
簡單實現(xiàn)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請求的內(nèi)容是拼接在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.創(chuàng)建請求會話
NSURLSession *session = [NSURLSession sharedSession];
// 2.創(chuàng)建請求
NSURLRequest *request = [NSURLRequest requestWithURL:URLcomponents.URL];
// 3.創(chuàng)建請求任務
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";
//根據(jù)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
然后呢鹦马,就會發(fā)現(xiàn)這個看起來太臃腫,并且很明顯忆肾,在Get請求和Post請求都涉及到NSURLSession和NSURLSessionDataTask荸频,只是在NSURLRequest的處理上有差異,所以我們可以進一步將NSURLSessionDataTask進行封裝客冈,完了之后結(jié)果如下:
- (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.創(chuàng)建請求
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];
}