写代码没有什么具体的规范和方式,只是哪个更加合理罢了。
老的项目HTTP请求使用的是AFNetworking找个优秀的第三方框架。由于使用不当导致各种代码耦合到一个类里,功能是满足了,但是可读性比较差,所以我对此进行了重构。
HIHTTPSessionManager
这个类是AFHTTPSessionManager的一个管理类,不涉及任何业务的代码。
.h
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
/// This class is a manager of the HTTP request, there will use AFNetworking send a request in this class. Never add the App business code in this class.
@interface HIHTTPSessionManager : NSObject
+ (nullable NSURLSessionDataTask *)POST:(NSString *)URLString
parameters:(nullable id)parameters
progress:(nullable void (^)(NSProgress *uploadProgress))uploadProgress
success:(nullable void (^)(NSURLSessionDataTask *task, id _Nullable responseObject))success
failure:(nullable void (^)(NSURLSessionDataTask * _Nullable task, NSError *error))failure;
+ (nullable NSURLSessionDataTask *)GET:(NSString *)URLString
parameters:(nullable id)parameters
progress:(nullable void (^)(NSProgress *downloadProgress))downloadProgress
success:(nullable void (^)(NSURLSessionDataTask *task, id _Nullable responseObject))success
failure:(nullable void (^)(NSURLSessionDataTask * _Nullable task, NSError *error))failure;
@end
.m
#import "HIHTTPSessionManager.h"
#import "AFHTTPSessionManager.h"
@implementation HIHTTPSessionManager
static AFHTTPSessionManager *_httpSessionManager = nil;
+ (AFHTTPSessionManager *)httpSessionManager {
if (_httpSessionManager == nil) {
// httpSessionManager
_httpSessionManager = [[AFHTTPSessionManager alloc] init];
// request out time set
_httpSessionManager.requestSerializer.timeoutInterval = 20.f;
// response serializer set
AFHTTPResponseSerializer *responseSerializer = [AFHTTPResponseSerializer serializer];
responseSerializer.acceptableContentTypes = [NSSet setWithObjects:@"application/json", @"text/json", @"text/javascript", @"text/html", @"text/xml", @"text/plain", nil];
_httpSessionManager.responseSerializer = responseSerializer;
// none securityPolicy
_httpSessionManager.securityPolicy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeNone];
}
return _httpSessionManager;
}
+ (nullable NSURLSessionDataTask *)POST:(NSString *)URLString
parameters:(nullable id)parameters
progress:(nullable void (^)(NSProgress *uploadProgress))uploadProgress
success:(nullable void (^)(NSURLSessionDataTask *task, id _Nullable responseObject))success
failure:(nullable void (^)(NSURLSessionDataTask * _Nullable task, NSError *error))failure
{
return [[HIHTTPSessionManager httpSessionManager] POST:URLString parameters:parameters progress:uploadProgress success:success failure:failure];
}
+ (nullable NSURLSessionDataTask *)GET:(NSString *)URLString
parameters:(nullable id)parameters
progress:(nullable void (^)(NSProgress *downloadProgress))downloadProgress
success:(nullable void (^)(NSURLSessionDataTask *task, id _Nullable responseObject))success
failure:(nullable void (^)(NSURLSessionDataTask * _Nullable task, NSError *error))failure
{
return [[HIHTTPSessionManager httpSessionManager]GET:URLString parameters:parameters progress:downloadProgress success:success failure:failure];
}
@end
HIHTTPRequestManager
这个类是对HIHTTPSessionManager的封装,对HTTP请求任务的封装,也不涉及业务代码。
.h
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
/// Ues this class to send the http request and manager the request task.
@interface HIHTTPRequestManager : NSObject
// Init
- (instancetype)init NS_UNAVAILABLE;
+ (instancetype)manager;
// GET.
- (void)GETWithRequestTag:(NSInteger)requestTag
URLString:(NSString *)URLString
parameters:(nullable id)parameters
progress:(nullable void (^)(NSProgress *progress))progressCallback
success:(nullable void (^)(NSURLSessionDataTask * _Nullable task, id result))successCallback
failure:(nullable void (^)(NSURLSessionDataTask * _Nullable task, NSError *error))failureCallback;
// the requesting task set.
@property (nonatomic, strong, readonly) NSMutableSet *taskSet;
// cancel a request, cancel the request when dismiss before controller.
- (void)cancelTask:(NSInteger)requestTag;
@end
NS_ASSUME_NONNULL_END
.m
#import "HIHTTPRequestManager.h"
#import "HIHTTPSessionManager.h"
@interface HIHTTPRequestManager ()
@property (nonatomic, strong, readwrite) NSMutableSet *taskSet;
@end
@implementation HIHTTPRequestManager
- (NSMutableSet *)taskSet {
if (!_taskSet) {
_taskSet = [[NSMutableSet alloc] init];
}
return _taskSet;
}
+ (instancetype)manager {
static HIHTTPRequestManager *_manager;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_manager = [[HIHTTPRequestManager alloc] init];
});
return _manager;
}
- (void)GETWithRequestTag:(NSInteger)requestTag
URLString:(NSString *)URLString
parameters:(nullable id)parameters
progress:(nullable void (^)(NSProgress *progress))progressCallback
success:(nullable void (^)(NSURLSessionDataTask * _Nullable task, id result))successCallback
failure:(nullable void (^)(NSURLSessionDataTask * _Nullable task, NSError *error))failureCallback
{
__weak typeof(self)weakSelf = self;
NSURLSessionDataTask *task = [WMSHTTPSessionManager GET:URLString parameters:parameters progress:progressCallback success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
NSString *jsonString = [[NSString alloc] initWithData:responseObject encoding:NSUTF8StringEncoding];
NSData *jsonData = [jsonString dataUsingEncoding:NSUTF8StringEncoding];
NSError *err;
id response = [NSJSONSerialization JSONObjectWithData:jsonData options:NSJSONReadingMutableContainers error:&err];
if (err) {
response = jsonString;
}
wmsDispatch_main_async_safe(^{
[weakSelf removeTask:task];
});
if (successCallback) {
successCallback(task,response);
}
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
wmsDispatch_main_async_safe(^{
[weakSelf removeTask:task];
});
if (failureCallback) {
failureCallback(task,error);
}
}];
NSString *taskDescription = [self getTaskDescription:requestTag];
if (taskDescription) {
task.taskDescription = taskDescription;
[weakSelf.taskSet addObject:task];
}
}
#pragma mark - task manager
- (void)cancelTask:(NSInteger)requestTag
{
NSString *taskDescription = [self getTaskDescription:requestTag];
for (NSURLSessionDataTask *task in self.taskSet) {
if ([task.taskDescription isEqualToString:taskDescription]) {
if (task.state < NSURLSessionTaskStateCanceling) {
[task cancel];
}
[self.taskSet removeObject:task];
}
}
}
- (void)removeTask:(NSURLSessionDataTask *)task
{
if ([self.taskSet containsObject:task]) {
[self.taskSet removeObject:task];
}
}
- (void)addTask:(NSURLSessionDataTask *)task
{
[self.taskSet addObject:task];
}
- (NSString *)getTaskDescription:(NSInteger)requestTag
{
return [NSString stringWithFormat:@"WMSHTTPRequest: %ld",(long)requestTag];
}
@end
这里taskSet不要使用集合了,建议使用HashTable,使用集合会产生对象释放问题。
@interface HIHTTPRequestManager ()
@property (nonatomic, strong, readwrite, nullable) NSHashTable *taskSet;
@end
@implementation HIHTTPRequestManager
- (NSHashTable *)taskSet {
if (!_taskSet) {
_taskSet = [NSHashTable weakObjectsHashTable];
}
return _taskSet;
}
HIHTTPRequest
在这个类里面去处理项目的业务请求,通过HIHTTPRequestManager来发起HTTP请求。
这个类里面我们可以添加一些自己项目的业务代码,比如发请求时候检查网络状态,保存请求日志,检查Session是否过期等的业务代码。
注意事项
1、AFHTTPSessionManager弄成全局的
2、使用的时候注意下请求完后回调是在主线程还是异步线程,如果是在主线程的话,就不用再返回主线程了。
#ifndef wmsDispatch_queue_async_safe
#define wmsDispatch_queue_async_safe(queue, block)\
if (dispatch_queue_get_label(DISPATCH_CURRENT_QUEUE_LABEL) == dispatch_queue_get_label(queue)) {\
block();\
} else {\
dispatch_async(queue, block);\
}
#endif
#ifndef wmsDispatch_main_async_safe
#define wmsDispatch_main_async_safe(block) wmsDispatch_queue_async_safe(dispatch_get_main_queue(), block)
#endif