iOS 对AFHTTPSessionManager的二次封装,紧贴AFNetworking的思想,先判断在请求,严谨全面,基本满足需求

对AFHTTPSessionManager的二次封装,紧贴AFNetworking的思想,先判断在请求,严谨全面,基本满足需求
项目地址:https://github.com/douxindong/XDAFHTTPSessionManager.git
// QQ网络请求讨论群【iOS技术开发帝国】:581443677
参考
// http://www.jianshu.com/p/4b5d2d47833d
// http://www.cnblogs.com/QianChia/p/5768428.html#autoid-7-0-0
效果图:

效果图.png

代码结构.png

XDHTTPSessionManager.h
XDHTTPSessionManager.m
XDDownLoadData.h
XDDownLoadData.m
//
//  XDHTTPSessionManager.h
//  XDAFHTTPSessionManager
//
//  Created by 窦心东 on 2016/12/2.
//  Copyright © 2016年 窦心东. All rights reserved.
//  iOS - HTTPS
//  http://www.jianshu.com/p/4b5d2d47833d
//  QQ网络请求讨论群【iOS开发帝国Https群】:581443677
//  http://www.cnblogs.com/QianChia/p/5768428.html#autoid-7-0-0

#import <AFNetworking/AFNetworking.h>
#define XDWeak  __weak __typeof(self) weakSelf = self
/*! 过期属性或方法名提醒 */
#define XDNetManagerDeprecated(instead) __deprecated_msg(instead)
typedef NS_ENUM(NSUInteger,RequestMethod) {
    POST = 0,
    GET,
    PUT,
    PATCH,
    DELETE,
    HEAD
};
/*!定义请求类型的枚举 */
typedef NS_ENUM(NSUInteger, XDHttpRequestType)
{
    /*! get请求 */
    XDHttpRequestTypeGet = 0,
    /*! post请求 */
    XDHttpRequestTypePost,
    /*! put请求 */
    XDHttpRequestTypePut,
    /*! delete请求 */
    XDHttpRequestTypeDelete
};
typedef NS_ENUM(NSInteger, AFNetworkErrorType) {
    AFNetworkErrorType_TimedOut = NSURLErrorTimedOut,                //-1001 请求超时
    AFNetworkErrorType_UnURL = NSURLErrorUnsupportedURL,             //-1002 不支持的URL
    AFNetworkErrorType_NoNetWork = NSURLErrorNotConnectedToInternet, //-1009 断网
    AFNetworkErrorType_404Failed = NSURLErrorBadServerResponse,      //-1011 404 错误
    
    AFNetworkErrorType_3840Failed = 3840,                        //3840 请求或者返回不是纯json格式
};
typedef NS_ENUM(NSUInteger, XDNetworkStatus) {
    /** 未知网络*/
    XDNetworkStatusUnknown,
    /** 无网络*/
    XDNetworkStatusNotReachable,
    /** 手机网络*/
    XDNetworkStatusReachableViaWWAN,
    /** WIFI网络*/
    XDNetworkStatusReachableViaWiFi
};

/** 请求成功的Block */
typedef void(^HttpRequestSuccess)(id responseObject);

/** 请求失败的Block */
typedef void(^HttpRequestFailed)(NSError *error);

/** 缓存的Block */
typedef void(^HttpRequestCache)(id responseCache);

/** 上传或者下载的进度, Progress.completedUnitCount:当前大小 - Progress.totalUnitCount:总大小*/
typedef void (^HttpProgress)(NSProgress *progress);

/** 网络状态的Block*/
typedef void(^NetworkStatus)(XDNetworkStatus status);

/** 请求任务 */
typedef NSURLSessionTask XDURLSessionTask;

#pragma mark - 网络数据请求类

@interface XDHTTPSessionManager : NSObject

/**
 *  声明单例方法
 */
+(instancetype)shareManager;
/**
 *  开始监听网络状态
 */
+ (void)startMonitoringNetwork;

/**
 *  实时获取网络状态回调
 */
+ (void)networkStatusWithBlock:(NetworkStatus)status;

/**
 *  GET请求,无缓存
 *
 *  @param URL        请求地址
 *  @param parameters 请求参数
 *  @param progress   进度信息
 *  @param success    请求成功的回调
 *  @param failure    请求失败的回调
 *
 *  @return 返回的对象可取消请求,调用cancle方法
 */
+ (XDURLSessionTask *)GET:(NSString *)URL parameters:(NSDictionary *)parameters progress:(HttpProgress)progress success:(HttpRequestSuccess)success failure:(HttpRequestFailed)failure;

/**
 *  GET请求,自动缓存
 *
 *  @param URL           请求地址
 *  @param parameters    请求参数
 *  @param responseCache 缓存数据的回调
 *  @param progress      进度信息
 *  @param success       请求成功的回调
 *  @param failure       请求失败的回调
 *
 *  @return 返回的对象可取消请求,调用cancle方法
 */
+ (XDURLSessionTask *)GET:(NSString *)URL parameters:(NSDictionary *)parameters responseCache:(HttpRequestCache)responseCache progress:(HttpProgress)progress success:(HttpRequestSuccess)success failure:(HttpRequestFailed)failure;

/**
 *  POST请求,无缓存
 *
 *  @param URL        请求地址
 *  @param parameters 请求参数
 *  @param progress   进度信息
 *  @param success    请求成功的回调
 *  @param failure    请求失败的回调
 *
 *  @return 返回的对象可取消请求,调用cancle方法
 */
+ (XDURLSessionTask *)POST:(NSString *)URL parameters:(NSDictionary *)parameters progress:(HttpProgress)progress success:(HttpRequestSuccess)success failure:(HttpRequestFailed)failure;

/**
 *  POST请求,自动缓存
 *
 *  @param URL           请求地址
 *  @param parameters    请求参数
 *  @param responseCache 缓存数据的回调
 *  @param progress      进度信息
 *  @param success       请求成功的回调
 *  @param failure       请求失败的回调
 *
 *  @return 返回的对象可取消请求,调用cancle方法
 */
+ (XDURLSessionTask *)POST:(NSString *)URL parameters:(NSDictionary *)parameters responseCache:(HttpRequestCache)responseCache progress:(HttpProgress)progress success:(HttpRequestSuccess)success failure:(HttpRequestFailed)failure;
/*!
 *  网络请求的实例方法
 *
 *  @param type         get / post / put / delete
 *  @param urlString    请求的地址
 *  @param parameters    请求的参数
 *  @param successBlock 请求成功的回调
 *  @param failureBlock 请求失败的回调
 *  @param progress 进度
 */
+ (XDURLSessionTask *)ba_requestWithType:(XDHttpRequestType)type UrlString:(NSString *)urlString Parameters:(NSDictionary *)parameters progress:(HttpProgress)progress SuccessBlock:(HttpRequestSuccess)successBlock FailureBlock:(HttpRequestFailed)failureBlock XDNetManagerDeprecated("该方法已过期,请使用最新方法:+ (BAURLSessionTask *)ba_requestWithType:(BAHttpRequestType)type urlString:(NSString *)urlString parameters:(NSDictionary *)parameters successBlock:(BAResponseSuccess)successBlock failureBlock:(BAResponseFail)failureBlock progress:(BADownloadProgress)progress");
/**
 *  上传图片文件
 *
 *  @param URL        请求地址
 *  @param parameters 请求参数
 *  @param images     图片数组
 *  @param name       文件对应服务器上的字段
 *  @param fileName   文件名
 *  @param mimeType   图片文件的类型,例:png、jpeg(默认类型)....
 *  @param progress   上传进度信息
 *  @param success    请求成功的回调
 *  @param failure    请求失败的回调
 *
 *  @return 返回的对象可取消请求,调用cancle方法
 */
+ (XDURLSessionTask *)uploadWithURL:(NSString *)URL parameters:(NSDictionary *)parameters images:(NSArray<UIImage *> *)images name:(NSString *)name fileName:(NSString *)fileName mimeType:(NSString *)mimeType progress:(HttpProgress)progress success:(HttpRequestSuccess)success failure:(HttpRequestFailed)failure;

/**
 *  下载文件
 *
 *  @param URL      请求地址
 *  @param fileDir  文件存储目录(默认存储目录为Download)
 *  @param progress 文件下载的进度信息
 *  @param success  下载成功的回调(回调参数filePath:文件的路径)
 *  @param failure  下载失败的回调
 *
 *  @return 返回NSURLSessionDownloadTask实例,可用于暂停继续,暂停调用suspend方法,开始下载调用resume方法
 */
+ (XDURLSessionTask *)downloadWithURL:(NSString *)URL fileDir:(NSString *)fileDir progress:(HttpProgress)progress success:(void(^)(NSString *filePath))success failure:(HttpRequestFailed)failure;



@end

//
//  XDHTTPSessionManager.m
//  XDAFHTTPSessionManager
//
//  Created by 窦心东 on 2016/12/2.
//  Copyright © 2016年 窦心东. All rights reserved.
//

#import "XDHTTPSessionManager.h"
#import "XDNetWorkingCacheManager.h"
#ifdef DEBUG
#define XDLog(fmt, ...) NSLog((@"%s [Line %d] " fmt), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__);
#else
#define XDLog(...)
#endif
static NSMutableArray *tasks;
static XDHTTPSessionManager *XDSessionManager= nil;
static NetworkStatus _status;
@implementation XDHTTPSessionManager

#pragma mark - 实现声明单例方法 GCD
+(instancetype)shareManager{
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        XDSessionManager = [[XDHTTPSessionManager alloc]init];
    });
    return XDSessionManager;
}
+ (instancetype)allocWithZone:(struct _NSZone *)zone {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        XDSessionManager = [super allocWithZone:zone];
    });
    return XDSessionManager;
}
+ (instancetype)init {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        XDSessionManager = [super init];
        [self startMonitoringNetwork];
        
        
    });
    return XDSessionManager;
}
#pragma mark - 设置AFHTTPSessionManager相关属性

+ (AFHTTPSessionManager *)createAFHTTPSessionManager
{
    static AFHTTPSessionManager *manager = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        manager = [AFHTTPSessionManager manager];
        //设置请求参数的类型:HTTP (AFJSONRequestSerializer,AFHTTPRequestSerializer)
        manager.requestSerializer = [AFHTTPRequestSerializer serializer];
        //设置请求的超时时间
        manager.requestSerializer.timeoutInterval = 30.f;
        //设置服务器返回结果的类型:JSON (AFJSONResponseSerializer,AFHTTPResponseSerializer)
        manager.responseSerializer = [AFJSONResponseSerializer serializer];
        /**
         *  请求队列的最大并发数
         */
        //    manager.operationQueue.maxConcurrentOperationCount = 5;
        
        
        
        /*! 打开状态栏的等待菊花 */
        [AFNetworkActivityIndicatorManager sharedManager].enabled = YES;
        
        /*! 设置相应的缓存策略:此处选择不用加载也可以使用自动缓存【注:只有get方法才能用此缓存策略,NSURLRequestReturnCacheDataDontLoad】 */
        manager.requestSerializer.cachePolicy = NSURLRequestReloadIgnoringLocalCacheData;
        
        /*! 设置返回数据类型为 json, 分别设置请求以及相应的序列化器 */
        /*!
         根据服务器的设定不同还可以设置:
         json:[AFJSONResponseSerializer serializer](常用)
         http:[AFHTTPResponseSerializer serializer]
         */
        AFJSONResponseSerializer *response = [AFJSONResponseSerializer serializer];
        /*! 这里是去掉了键值对里空对象的键值 */
        response.removesKeysWithNullValues = YES;
        manager.responseSerializer = response;
        
        /* 设置请求服务器数类型式为 json */
        /*! 根据服务器的设定不同还可以设置 [AFJSONRequestSerializer serializer](常用) */
        AFJSONRequestSerializer *request = [AFJSONRequestSerializer serializer];
        manager.requestSerializer = request;
        
        /*! 设置apikey ------类似于自己应用中的tokken---此处仅仅作为测试使用*/
        //        [manager.requestSerializer setValue:apikey forHTTPHeaderField:@"apikey"];
        
        /*! 复杂的参数类型 需要使用json传值-设置请求内容的类型*/
        //        [manager.requestSerializer setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
        
        /*! 设置响应数据的基本类型 */
        manager.responseSerializer.acceptableContentTypes = [NSSet setWithObjects:@"application/json", @"text/json", @"text/javascript",@"text/html",@"text/css",@"text/xml",@"text/plain", @"application/javascript", @"image/*", nil];
        
        /*! https 参数配置 */
        /*!
         采用默认的defaultPolicy就可以了. AFN默认的securityPolicy就是它, 不必另写代码. AFSecurityPolicy类中会调用苹果security.framework的机制去自行验证本次请求服务端放回的证书是否是经过正规签名.
         */
        AFSecurityPolicy *securityPolicy = [AFSecurityPolicy defaultPolicy];
        securityPolicy.allowInvalidCertificates = YES;
        securityPolicy.validatesDomainName = NO;
        manager.securityPolicy = securityPolicy;
        
        /*! 自定义的CA证书配置如下: */
        /*! 自定义security policy, 先前确保你的自定义CA证书已放入工程Bundle */
        /*!
         https://api.github.com网址的证书实际上是正规CADigiCert签发的, 这里把Charles的CA根证书导入系统并设为信任后, 把Charles设为该网址的SSL Proxy (相当于"中间人"), 这样通过代理访问服务器返回将是由Charles伪CA签发的证书.
         */
        //        NSSet <NSData *> *cerSet = [AFSecurityPolicy certificatesInBundle:[NSBundle mainBundle]];
        //        AFSecurityPolicy *policy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeCertificate withPinnedCertificates:cerSet];
        //        policy.allowInvalidCertificates = YES;
        //        manager.securityPolicy = policy;
        
        /*! 如果服务端使用的是正规CA签发的证书, 那么以下几行就可去掉: */
        //        NSSet <NSData *> *cerSet = [AFSecurityPolicy certificatesInBundle:[NSBundle mainBundle]];
        //        AFSecurityPolicy *policy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeCertificate withPinnedCertificates:cerSet];
        //        policy.allowInvalidCertificates = YES;
        //        manager.securityPolicy = policy;
    });
    return manager;
}
#pragma mark - 开始监听网络
+ (void)startMonitoringNetwork
{
    AFNetworkReachabilityManager *manager = [AFNetworkReachabilityManager sharedManager];
    
    [manager setReachabilityStatusChangeBlock:^(AFNetworkReachabilityStatus status) {
        switch (status)
        {
            case AFNetworkReachabilityStatusUnknown:
                _status(XDNetworkStatusUnknown);
                XDLog(@"未知网络");
                break;
            case AFNetworkReachabilityStatusNotReachable:
                _status(XDNetworkStatusNotReachable);
                XDLog(@"无网络");
                break;
            case AFNetworkReachabilityStatusReachableViaWWAN:
                _status(XDNetworkStatusReachableViaWWAN);
                XDLog(@"手机自带网络");
                break;
            case AFNetworkReachabilityStatusReachableViaWiFi:
                _status(XDNetworkStatusReachableViaWiFi);
                XDLog(@"WIFI");
                break;
        }
    }];
    [manager startMonitoring];
    
}
+ (void)networkStatusWithBlock:(NetworkStatus)status
{
    _status = status;
}

#pragma mark - GET请求无缓存
+ (XDURLSessionTask *)GET:(NSString *)URL parameters:(NSDictionary *)parameters progress:(HttpProgress)progress success:(HttpRequestSuccess)success failure:(HttpRequestFailed)failure
{
    [UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
    AFHTTPSessionManager *manager = [self createAFHTTPSessionManager];
    return [manager GET:URL parameters:parameters progress:^(NSProgress * _Nonnull uploadProgress) {
        progress ? progress(uploadProgress) : nil;
    } success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
        [UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
        
        success?success(responseObject):nil;
        XDLog(@"responseObject = %@",responseObject);
        
    } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
        [UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
        
        failure ? failure(error) : nil;
        XDLog(@"error = %@",error);
    }];
}

#pragma mark - GET请求自动缓存
+ (XDURLSessionTask *)GET:(NSString *)URL parameters:(NSDictionary *)parameters responseCache:(HttpRequestCache)responseCache progress:(HttpProgress)progress success:(HttpRequestSuccess)success failure:(HttpRequestFailed)failure
{
    [UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
    //读取缓存
    responseCache?responseCache([XDNetWorkingCacheManager getResponseCacheForKey:URL]):nil;
    
    AFHTTPSessionManager *manager = [self createAFHTTPSessionManager];
    return [manager GET:URL parameters:parameters progress:^(NSProgress * _Nonnull uploadProgress) {
        progress ? progress(uploadProgress) : nil;
    } success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
        [UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
        
        success?success(responseObject):nil;
        //对数据进行异步缓存
        [XDNetWorkingCacheManager saveResponseCache:responseObject forKey:URL];
        XDLog(@"responseObject = %@",responseObject);
        
    } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
        [UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
        
        failure ? failure(error) : nil;
        XDLog(@"error = %@",error);
        
    }];
}

#pragma mark - POST请求无缓存
+ (XDURLSessionTask *)POST:(NSString *)URL parameters:(NSDictionary *)parameters progress:(HttpProgress)progress success:(HttpRequestSuccess)success failure:(HttpRequestFailed)failure
{
    [UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
    
    AFHTTPSessionManager *manager = [self createAFHTTPSessionManager];
    return [manager POST:URL parameters:parameters progress:^(NSProgress * _Nonnull uploadProgress) {
        progress ? progress(uploadProgress) : nil;
    } success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
        [UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
        
        success?success(responseObject):nil;
        XDLog(@"responseObject = %@",responseObject);
    } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
        [UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
        
        failure ? failure(error) : nil;
        XDLog(@"error = %@",error);
    }];
    
}

#pragma mark - POST请求自动缓存
+ (XDURLSessionTask *)POST:(NSString *)URL parameters:(NSDictionary *)parameters responseCache:(HttpRequestCache)responseCache progress:(HttpProgress)progress success:(HttpRequestSuccess)success failure:(HttpRequestFailed)failure
{
    [UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
    
    //读取缓存
    responseCache?responseCache([XDNetWorkingCacheManager getResponseCacheForKey:URL]):nil;
    
    AFHTTPSessionManager *manager = [self createAFHTTPSessionManager];
    return [manager POST:URL parameters:parameters progress:^(NSProgress * _Nonnull uploadProgress) {
        progress ? progress(uploadProgress) : nil;
    } success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
        [UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
        
        success?success(responseObject): nil;
        //对数据进行异步缓存
        [XDNetWorkingCacheManager saveResponseCache:responseObject forKey:URL];
        XDLog(@"responseObject = %@",responseObject);
        
    } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
        [UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
        
        failure ? failure(error) : nil;
        XDLog(@"error = %@",error);
    }];
    
}
#pragma mark - 网络请求的类方法 --- get / post / put / delete
/*!
 *  网络请求的实例方法
 *
 *  @param type         get / post / put / delete
 *  @param urlString    请求的地址
 *  @param parameters    请求的参数
 *  @param successBlock 请求成功的回调
 *  @param failureBlock 请求失败的回调
 *  @param progress 进度
 */
+ (XDURLSessionTask *)ba_requestWithType:(XDHttpRequestType)type UrlString:(NSString *)urlString Parameters:(NSDictionary *)parameters progress:(HttpProgress)progress SuccessBlock:(HttpRequestSuccess)successBlock FailureBlock:(HttpRequestFailed)failureBlock
{
    if (urlString == nil)
    {
        return nil;
    }
    
    XDWeak;
    /*! 检查地址中是否有中文 */
    NSString *URLString = [NSURL URLWithString:urlString] ? urlString : [self strUTF8Encoding:urlString];
    
    NSString *requestType;
    switch (type) {
        case 0:
            requestType = @"Get";
            break;
        case 1:
            requestType = @"Post";
            break;
        case 2:
            requestType = @"Put";
            break;
        case 3:
            requestType = @"Delete";
            break;
            
        default:
            break;
    }
    
    NSLog(@"******************** 请求参数 ***************************");
    NSLog(@"请求头: %@\n请求方式: %@\n请求URL: %@\n请求param: %@\n\n",[self createAFHTTPSessionManager].requestSerializer.HTTPRequestHeaders, requestType, URLString, parameters);
    NSLog(@"********************************************************");
    
    XDURLSessionTask *sessionTask = nil;
    
    if (type == XDHttpRequestTypeGet)
    {
        
        
        sessionTask = [[self createAFHTTPSessionManager] GET:URLString parameters:parameters  progress:^(NSProgress * _Nonnull downloadProgress) {
            progress?progress(downloadProgress):nil;
        } success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
            
            /****************************************************/
            // 如果请求成功 , 回调请求到的数据 , 同时 在这里 做本地缓存
            NSString *path = [NSString stringWithFormat:@"%ld.plist", [URLString hash]];
            // 存储的沙盒路径
            NSString *path_doc = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject];
            NSLog(@"如果请求成功 , 回调请求到的数据 , 同时 在这里 做本地缓存,存储的沙盒路径:%@",path_doc);
            // 归档
            [NSKeyedArchiver archiveRootObject:responseObject toFile:[path_doc stringByAppendingPathComponent:path]];
            
            successBlock?successBlock(responseObject):nil;
            
            [[weakSelf tasks] removeObject:sessionTask];
            
            //[self writeInfoWithDict:(NSDictionary *)responseObject];
            
        } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
            
            failureBlock?failureBlock(error):nil;
            NSLog(@"错误信息:%@",error);
            [[weakSelf tasks] removeObject:sessionTask];
            
        }];
        
    }
    else if (type == XDHttpRequestTypePost)
    {
        sessionTask = [[self createAFHTTPSessionManager] POST:URLString parameters:parameters progress:^(NSProgress * _Nonnull uploadProgress) {
             progress?progress(uploadProgress):nil;
        } success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
            
            /* ************************************************** */
            // 如果请求成功 , 回调请求到的数据 , 同时 在这里 做本地缓存
            NSString *path = [NSString stringWithFormat:@"%ld.plist", [URLString hash]];
            // 存储的沙盒路径
            NSString *path_doc = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject];
            NSLog(@"如果请求成功 , 回调请求到的数据 , 同时 在这里 做本地缓存,存储的沙盒路径:%@",path_doc);
            // 归档
            [NSKeyedArchiver archiveRootObject:responseObject toFile:[path_doc stringByAppendingPathComponent:path]];
            
            successBlock?successBlock(responseObject):nil;
            
            [[weakSelf tasks] removeObject:sessionTask];
            
        } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
            
            failureBlock?failureBlock(error):nil;
                NSLog(@"错误信息:%@",error);
            [[weakSelf tasks] removeObject:sessionTask];
            
        }];
    }
    else if (type == XDHttpRequestTypePut)
    {
        sessionTask = [[self createAFHTTPSessionManager] PUT:URLString parameters:parameters success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
            
            if (successBlock)
            {
                successBlock(responseObject);
            }
            
            [[weakSelf tasks] removeObject:sessionTask];
            
            //[self writeInfoWithDict:(NSDictionary *)responseObject];
            
        } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
            
            if (failureBlock)
            {
                failureBlock(error);
            }
            [[weakSelf tasks] removeObject:sessionTask];
            
        }];
    }
    else if (type == XDHttpRequestTypeDelete)
    {
        sessionTask = [[self createAFHTTPSessionManager] DELETE:URLString parameters:parameters success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
            if (successBlock)
            {
                successBlock(responseObject);
            }
            
            [[weakSelf tasks] removeObject:sessionTask];
            
//            [self writeInfoWithDict:(NSDictionary *)responseObject];
            
        } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
            
            if (failureBlock)
            {
                failureBlock(error);
            }
            [[weakSelf tasks] removeObject:sessionTask];
            
        }];
    }
    
    if (sessionTask)
    {
        [[weakSelf tasks] addObject:sessionTask];
    }
    
    return sessionTask;
}


#pragma mark - 上传图片文件
+ (XDURLSessionTask *)uploadWithURL:(NSString *)URL parameters:(NSDictionary *)parameters images:(NSArray<UIImage *> *)images name:(NSString *)name fileName:(NSString *)fileName mimeType:(NSString *)mimeType progress:(HttpProgress)progress success:(HttpRequestSuccess)success failure:(HttpRequestFailed)failure
{
    [UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
    
    AFHTTPSessionManager *manager = [self createAFHTTPSessionManager];
    return [manager POST:URL parameters:parameters constructingBodyWithBlock:^(id<AFMultipartFormData>  _Nonnull formData) {
        
        //压缩-添加-上传图片
        [images enumerateObjectsUsingBlock:^(UIImage * _Nonnull image, NSUInteger idx, BOOL * _Nonnull stop) {
            NSData *imageData = [NSData data];
            if (UIImagePNGRepresentation(image) == nil) {
                imageData = UIImageJPEGRepresentation(image, 1);
            } else {
                imageData = UIImagePNGRepresentation(image);
            }
            
            [formData appendPartWithFileData:imageData name:name fileName:[NSString stringWithFormat:@"%@%ld.%@",fileName,idx,mimeType?mimeType:@"jpeg"] mimeType:[NSString stringWithFormat:@"image/%@",mimeType?mimeType:@"jpeg"]];
        }];
    } progress:^(NSProgress * _Nonnull uploadProgress) {
        //上传进度
        progress ? progress(uploadProgress) : nil;
        
    } success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
        [UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
        
        success?success(responseObject): nil;
        XDLog(@"responseObject = %@",responseObject);
    } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
        [UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
        
        failure ? failure(error) : nil;
        XDLog(@"error = %@",error);
    }];
}

#pragma mark - 下载文件
+ (XDURLSessionTask *)downloadWithURL:(NSString *)URL fileDir:(NSString *)fileDir progress:(HttpProgress)progress success:(void(^)(NSString *))success failure:(HttpRequestFailed)failure
{
    [UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
    
    AFHTTPSessionManager *manager = [self createAFHTTPSessionManager];
    NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:URL]];
    NSURLSessionDownloadTask *downloadTask = [manager downloadTaskWithRequest:request progress:^(NSProgress * _Nonnull downloadProgress) {
        //下载进度
        progress ? progress(downloadProgress) : nil;
        XDLog(@"下载进度:%.2f%%",100.0*downloadProgress.completedUnitCount/downloadProgress.totalUnitCount);
        
    } destination:^NSURL * _Nonnull(NSURL * _Nonnull targetPath, NSURLResponse * _Nonnull response) {
        
        
        //拼接缓存目录
        NSString *downloadDir = [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:fileDir ? fileDir : @"Download"];
        //打开文件管理器
        NSFileManager *fileManager = [NSFileManager defaultManager];
        
        //创建Download目录
        [fileManager createDirectoryAtPath:downloadDir withIntermediateDirectories:YES attributes:nil error:nil];
        
        //拼接文件路径
        NSString *filePath = [downloadDir stringByAppendingPathComponent:response.suggestedFilename];
        
        XDLog(@"下载文件所在文件夹downloadDir = %@",downloadDir);
        
        //返回文件位置的URL路径
        return [NSURL fileURLWithPath:filePath];
        
    } completionHandler:^(NSURLResponse * _Nonnull response, NSURL * _Nullable filePath, NSError * _Nullable error) {
        [UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
        
        success ? success(filePath.absoluteString /** NSURL->NSString*/) : nil;
        failure && error ? failure(error) : nil;
        
    }];
    
    //开始下载
    [downloadTask resume];
    
    return downloadTask;
    
}
#pragma mark -- POST/GET网络请求 --
+ (XDURLSessionTask *)requestWithURLString:(NSString *)URLString
                                parameters:(id)parameters
                             requestMethod:(RequestMethod)method
                                   success:(void (^)(id))success
                                   failure:(void (^)(NSError *))failure {
    
    
    switch (method) {
        case GET:
        {
            AFHTTPSessionManager *manager = [self createAFHTTPSessionManager];
            return [manager GET:URLString parameters:nil progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
                if (success) {
                    success(responseObject);
                }
            } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
                if (failure) {
                    failure(error);
                }
            }];
        }
            break;
        case POST:
        {
            AFHTTPSessionManager *manager = [self createAFHTTPSessionManager];
            return [manager POST:URLString parameters:parameters progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
                if (success) {
                    success(responseObject);
                }
            } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
                if (failure) {
                    failure(error);
                }
            }];
        }
        case PUT:
        {
            NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:
                                                                                URLString]];
            request.HTTPMethod = @"PUT";
            
            //            [request setValue:[@"admin:adminpasswd" q_basic64AuthEncode] forHTTPHeaderField:@"Authorization"];
            
            NSURL *fileURL = [[NSBundle mainBundle] URLForResource:@"HQ_0005.jpg" withExtension:nil];
            
            AFURLSessionManager *manager = [[AFURLSessionManager alloc]
                                            initWithSessionConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]];
            manager.responseSerializer = [AFHTTPResponseSerializer serializer];
            NSURLSessionUploadTask * UploadTask = [manager uploadTaskWithRequest:request fromFile:fileURL progress:^(NSProgress * _Nonnull uploadProgress) {
                
                //                float progress = 1.0 * uploadProgress.completedUnitCount / uploadProgress.totalUnitCount;
                //                dispatch_async(dispatch_get_main_queue(), ^{
                //                    [self.progressBtn q_setButtonWithProgress:progress lineWidth:10 lineColor:nil backgroundColor:[UIColor yellowColor]];
                //                });
                
            } completionHandler:^(NSURLResponse * _Nonnull response, id  _Nullable responseObject, NSError * _Nullable error) {
                
                if (error == nil && responseObject != nil) {
                    NSLog(@"success: %@ --- %@", responseObject, [responseObject class]);
                } else {
                    NSLog(@"failure: %@", error);
                }
            }];
            [UploadTask resume];
            return UploadTask;
            
        }
        case PATCH:
        {
            return nil;
        }
        case DELETE:
        {
            return nil;
        }
        case HEAD:
        {
            AFHTTPSessionManager *manager = [self createAFHTTPSessionManager];
            return [manager HEAD:URLString parameters:nil success:^(NSURLSessionDataTask * _Nonnull task) {
                
                NSLog(@"success: %@ --- %lld", task.response.suggestedFilename, task.response.expectedContentLength);
                
            } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
                
                NSLog(@"failure: %@", error);
            }];
        }
            break;
    }
}



#pragma mark - url 中文格式化
+ (NSString *)strUTF8Encoding:(NSString *)str
{
    /*! ios9适配的话 打开第一个 */
    if ([[UIDevice currentDevice] systemVersion].floatValue >= 9.0)
    {
        return [str stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLPathAllowedCharacterSet]];
    }
    else
    {
        return [str stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
    }
}
+ (NSMutableArray *)tasks
{
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        NSLog(@"创建任务数组");
        tasks = [[NSMutableArray alloc] init];
    });
    return tasks;
}

@end

//
//  XDDownLoadData.h
//  XDAFHTTPSessionManager
//
//  Created by 窦心东 on 2016/12/2.
//  Copyright © 2016年 窦心东. All rights reserved.
//

#import <Foundation/Foundation.h>

@interface XDDownLoadData : NSObject
singleton_interface(XDDownLoadData)
@property (nonatomic, strong) AFURLSessionManager *manager;
@property (nonatomic, retain) NSURLSessionDownloadTask *downloadTask;

@property (nonatomic, strong) NSData   *resumeData;
@property (nonatomic, strong) NSString *resumeTmpPath;

@property (nonatomic, assign) BOOL isDownloading;
@property (nonatomic, assign) BOOL isPause;
- (NSString *)resumeTmpPath;
// 开始下载
- (void)start;
// 继续下载
- (void)goon;
// 暂停下载
- (void)pause;
// 停止下载
- (void)stop;
- (void)downloadProgress:(NSProgress *)downloadProgress;
- (void)downloadCompletion:(NSURL *)filePath error:(NSError *)error;
@end

//
//  XDDownLoadData.m
//  XDAFHTTPSessionManager
//
//  Created by 窦心东 on 2016/12/2.
//  Copyright © 2016年 窦心东. All rights reserved.
//

#import "XDDownLoadData.h"

@implementation XDDownLoadData

singleton_implementation(XDDownLoadData)
- (AFURLSessionManager *)manager {
    if (_manager == nil) {
        _manager = [[AFURLSessionManager alloc] initWithSessionConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]];
        _manager.responseSerializer = [AFHTTPResponseSerializer serializer];
    }
    return _manager;
}

- (NSString *)resumeTmpPath {
    if (_resumeTmpPath == nil) {
        _resumeTmpPath = [@"resumeTmpData.tmp" q_appendCachePath];
    }
    return _resumeTmpPath;
}

// 开始下载

- (void)start {
    
    if (self.isDownloading) {
        NSLog(@"已经开始下载");
        return;
    }
    
    if (self.isPause) {
        
        NSLog(@"继续下载");
        
        [self.downloadTask resume];
        
        self.isPause = NO;
        self.isDownloading = YES;
        return;
    }
    //如果内存中 这个路径的文件不在或者没有大小, 就进行开始 ;  反之有的话,继续下载
    if (![[NSFileManager defaultManager] fileExistsAtPath:self.resumeTmpPath]) {
        
        NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"http://120.25.226.186:32812/resources/videos/minion_01.mp4"]];
        
        self.downloadTask = [self.manager downloadTaskWithRequest:request progress:^(NSProgress * _Nonnull downloadProgress) {
            
            [self downloadProgress:downloadProgress];
            
        } destination:^NSURL * _Nonnull(NSURL * _Nonnull targetPath, NSURLResponse * _Nonnull response) {
            
            return [NSURL fileURLWithPath:[response.suggestedFilename q_appendDocumentPath]];
            
        } completionHandler:^(NSURLResponse * _Nonnull response, NSURL * _Nullable filePath, NSError * _Nullable error) {
            
            [self downloadCompletion:filePath error:error];
        }];
        
        [self.downloadTask resume];
        
        self.isPause = NO;
        self.isDownloading = YES;
        
    } else {
        [self goon];
    }
}

// 继续下载

- (void)goon {
    
    if (self.isDownloading) {
        NSLog(@"已经开始下载");
        return;
    }
    
    if (self.isPause) {
        
        [self.downloadTask resume];
        NSLog(@"继续下载");
        
    } else {
        
        self.resumeData = [NSData dataWithContentsOfFile:self.resumeTmpPath];
        
        self.downloadTask = [self.manager downloadTaskWithResumeData:self.resumeData progress:^(NSProgress * _Nonnull downloadProgress) {
            
            [self downloadProgress:downloadProgress];
        } destination:^NSURL * _Nonnull(NSURL * _Nonnull targetPath, NSURLResponse * _Nonnull response) {
            
            return [NSURL fileURLWithPath:[response.suggestedFilename q_appendDocumentPath]];
        } completionHandler:^(NSURLResponse * _Nonnull response, NSURL * _Nullable filePath, NSError * _Nullable error) {
            
            [self downloadCompletion:filePath error:error];
        }];
        
        [self.downloadTask resume];
        
        NSLog(@"继续下载");
    }
    
    self.isPause = NO;
    self.isDownloading = YES;
}

// 暂停下载

- (void)pause {
    
    if (!self.isDownloading) {
        NSLog(@"已经停止下载");
        return;
    }
    
    [self.downloadTask suspend];
    
    NSLog(@"暂停下载");
    
    self.isPause = YES;
    self.isDownloading = NO;
}

// 停止下载

- (void)stop {
    
    if (!self.isDownloading) {
        NSLog(@"已经停止下载");
        return;
    }
    
    [self.downloadTask cancelByProducingResumeData:^(NSData * _Nullable resumeData) {
        
        if (resumeData) {
            
            self.resumeData = resumeData;
            
            [self.resumeData writeToFile:self.resumeTmpPath atomically:YES];
        }
        
        self.downloadTask = nil;
        
        NSLog(@"停止下载");
    }];
    
    self.isDownloading = NO;
}

- (void)downloadProgress:(NSProgress *)downloadProgress {
    
    float progress = (1.0 *downloadProgress.completedUnitCount / downloadProgress.totalUnitCount)*100;
    
    dispatch_async(dispatch_get_main_queue(), ^{
//                [self.progressBtn q_setButtonWithProgress:progress lineWidth:10 lineColor:nil backgroundColor:[UIColor yellowColor]];
        NSLog(@"进度%.0f%%",progress);
    });
}

- (void)downloadCompletion:(NSURL *)filePath error:(NSError *)error {
    
    self.isDownloading = NO;
    
    if (error == nil) {
        
        NSLog(@"success: %@", filePath.path);
        
        [[NSFileManager defaultManager] removeItemAtPath:self.resumeTmpPath error:nil];
        
    } else {
        
        NSLog(@"%@", error);
        
        if (error) {
            NSLog(@"failure: %@", error.userInfo[NSLocalizedDescriptionKey]);
            
            self.resumeData = error.userInfo[NSURLSessionDownloadTaskResumeData];
        }
        
        if ([error.localizedFailureReason isEqualToString:@"No such file or directory"]) {
            
            [[NSFileManager defaultManager] removeItemAtPath:self.resumeTmpPath error:nil];
            
            [self start];
        }
    }
}
@end

//
//  ViewController.m
//  XDAFHTTPSessionManager
//
//  Created by 窦心东 on 2016/12/2.
//  Copyright © 2016年 窦心东. All rights reserved.
//

#import "ViewController.h"
#import "XDDownLoadData.h"
#import "XDHTTPSessionManager.h"
#define XDSessionManager [XDHTTPSessionManager shareManager]
#define DownLoadData [XDDownLoadData sharedXDDownLoadData]
@interface ViewController (){
    UIButton *button;
}


@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    
    //    button = [UIButton buttonWithType:UIButtonTypeCustom];
    //    [button setTitle:@"开始" forState:UIControlStateNormal];
    //    [button setBackgroundColor:[UIColor redColor]];
    //    button.frame = CGRectMake(100, 100, 100, 100);
    //    [self.view addSubview:button];
    //    [button addTarget:self action:@selector(buttonclick) forControlEvents:UIControlEventTouchUpInside];
    
}
- (void)buttonclick{
    //封装好了,展示需要自己写,这仅仅是显示一下更高深的 需要自行使用API
    if ([button.titleLabel.text isEqualToString:@"开始"]) {
        [button setTitle:@"暂停" forState:UIControlStateNormal];
        [DownLoadData start];
    } else {
        [button setTitle:@"开始" forState:UIControlStateNormal];
        [DownLoadData pause];
    }
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
   
    //当前只示例两个 其他方式一样的形式
    //进行数据下载
    [self download];
    //进行post请求
    [self postData];
    
    
    
    
    
}

- (void)download{
    [XDHTTPSessionManager downloadWithURL:@"http://120.25.226.186:32812/resources/videos/minion_01.mp4" fileDir:@"video" progress:^(NSProgress *progress) {
        [DownLoadData downloadProgress:progress];
    } success:^(NSString *filePath) {
        NSLog(@"全路径是filePath.absoluteString ======%@",filePath);
    } failure:^(NSError *error) {
        NSLog(@"error == %@",error);
    }];

}
- (void)postData{
    NSDictionary *parameters = @{
                                 @"pageNo":@1,
                                 @"pageSize":@"20"
                                 };
    [XDHTTPSessionManager POST:@"http://115.28.11.62:8080/heal/api/heal/plan/list" parameters:parameters progress:^(NSProgress *progress) {
        [DownLoadData downloadProgress:progress];
    } success:^(id responseObject) {
        
        NSLog(@"responseObject%@",[responseObject yy_modelDescription]);
    } failure:^(NSError *error) {
        NSLog(@"error==%@",error);
    }];
}
- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}


@end

项目地址:https://github.com/douxindong/XDAFHTTPSessionManager.git

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,491评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,856评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,745评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,196评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,073评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,112评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,531评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,215评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,485评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,578评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,356评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,215评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,583评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,898评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,174评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,497评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,697评论 2 335

推荐阅读更多精彩内容

  • afinalAfinal是一个android的ioc,orm框架 https://github.com/yangf...
    passiontim阅读 15,360评论 2 44
  • 我想时间在长点
    窮奇阅读 96评论 0 3
  • 当我三四岁时,我感觉父亲是天底下最强壮的人; 和大多数孩子一样,四五岁的我很喜欢出去玩,可能被困在家里的时间太多,...
    安敢心阅读 807评论 0 50
  • 以前一直听四川的朋友说樱桃好吃,但是在广东确实没有见过这个水果。 今天办公室同事给我分了一点,这是我第一次吃樱桃,...
    钟汉明zZ阅读 145评论 2 0
  • 表扬自己一个 我之前一直喜欢脑海里judge别人,今天克制住了这个念头。可能没这个腹黑习惯的人看起来没啥,但是对我...
    迷茫de帅阅读 171评论 0 0