• 第六十二篇、AFN3.0封装网络请求框架,支持缓存


    1.网络请求

    第一种实现方式:

      功能:GET POST 请求

    缓存逻辑:

      1.是否要刷新本地缓存,不需要就直接发起无缓存的网络请求,否则直接读取本地数据

      2.需要刷新本地缓存,先读取本地数据,有就返回,没有就发起缓存的网络请求

      3.无网络时直接读取本地缓存

    #import "AFHTTPSessionManager.h"
    
    /**
       *该类默认只要导入头文件就会自动检测网络状态,且会在没有网络和未知网络的时候,自动从本地数据库中读取缓存。
       *数据库网络缓存是基于猿题库公司对FMDB进行封装的轻量级 key-value 存储框架
       *详情请见 https://github.com/yuantiku/YTKKeyValueStore  
       *对该类如有疑问可以拉个issues
     */
    @interface JMHttpRequestMethod : AFHTTPSessionManager
    
    typedef NS_ENUM(NSUInteger, JMRequestSerializer) {
        JMRequestSerializerJSON,     // 设置请求数据为JSON格式
        JMRequestSerializerPlainText    // 设置请求数据为普通 text/html
    };
    
    typedef NS_ENUM(NSUInteger, JMResponseSerializer) {
        JMResponseSerializerJSON,    // 设置响应数据为JSON格式
        JMResponseSerializerHTTP,    // 设置响应数据为二进制格式
        JMResponseSerializerXML      // 设置响应数据为XML格式
    };
    
    #pragma mark - 程序入口设置网络请求头API  一般调用一次即可
    
    /**
      设置 请求和响应类型和超时时间
     @param requestType  默认为请求类型为JSON格式
     @param responseType 默认响应格式为JSON格式
     @param timeOut      请求超时时间 默认为20秒
     */
    +(void)setTimeOutWithTime:(NSTimeInterval)timeOut
                  requestType:(JMRequestSerializer)requestType
                 responseType:(JMResponseSerializer)responseType;
    
    /**
     设置 请求头
     @param httpBody 根据服务器要求 配置相应的请求体
     */
    + (void)setHttpBodyWithDic:(NSDictionary *)httpBody;
    
    #pragma mark - 网络工具 API
    /**
     获取当前的网络状态
     
     @return YES 有网  NO 没有联网
     */
    +(BOOL)getCurrentNetWorkStatus;
    
    /**
     获取网络缓存 文件大小
     @return size  单位M 默认保留两位小数 如: 0.12M
     */
    + (NSString *)fileSizeWithDBPath;
    /**
     清除所有网络缓存
     */
    + (void)cleanNetWorkRefreshCache;
    
    #pragma mark -  GET 请求API
    
    /**
     GET 请求  不用传参 API
     @param url          请求的url
     @param refreshCache 是否对该页面进行缓存
     @param success      请求成功回调
     @param fail         请求失败回调
     @return self
     */
    + (JMHttpRequestMethod *)getWithUrl:(NSString *)url
                           refreshCache:(BOOL)refreshCache
                                success:(void(^)(id responseObject))success
                                   fail:(void(^)(NSError *error))fail;
    
    /**
     GET 请求 传参数的API
     @param url          请求的url
     @param refreshCache 是否对该页面进行缓存
     @param params       请求数据向服务器传的参数
     @param success        请求成功回调
     @param fail         请求失败回调
     @return self
     */
    + (JMHttpRequestMethod *)getWithUrl:(NSString *)url
                           refreshCache:(BOOL)refreshCache
                                 params:(NSDictionary *)params
                                success:(void(^)(id responseObject))success
                                   fail:(void(^)(NSError *error))fail;
    
    /**
     GET 请求 带有进度回调的 API
     @param url               请求的url
     @param refreshCache 是否对该页面进行缓存
     @param params       请求数据向服务器传的参数
     @param progress     请求进度回调
     @param success      请求成功回调
     @param fail         请求失败回调
     @return self
     */
    + (JMHttpRequestMethod *)getWithUrl:(NSString *)url
                           refreshCache:(BOOL)refreshCache
                                 params:(NSDictionary *)params
                               progress:(void(^)(int64_t bytesRead, int64_t totalBytesRead))progress
                                success:(void(^)(id responseObject))success
                                   fail:(void(^)(NSError *error))fail;
    
    
    #pragma mark -  POST 请求API
    
    
    /**
     POST 请求API
     @param url          请求的url
     @param refreshCache 是否对该页面进行缓存
     @param params       请求数据向服务器传的参数
     @param success      请求成功回调
     @param fail         请求失败回调
     @return self
     */
    + (JMHttpRequestMethod *)postWithUrl:(NSString *)url
                            refreshCache:(BOOL)refreshCache
                                  params:(NSDictionary *)params
                                 success:(void(^)(id responseObject))success
                                    fail:(void(^)(NSError *error))fail;
    
    
    /**
     POST 请求 带有进度回调的 API
     
     @param url               请求的url
     @param refreshCache 是否对该页面进行缓存
     @param params       请求数据向服务器传的参数
     @param progress     请求进度回调
     @param success      请求成功回调
     @param fail         请求失败回调
     
     @return self
     */
    + (JMHttpRequestMethod *)postWithUrl:(NSString *)url
                            refreshCache:(BOOL)refreshCache
                                  params:(NSDictionary *)params
                                progress:(void(^)(int64_t bytesRead, int64_t totalBytesRead))progress
                                 success:(void(^)(id responseObject))success
                                    fail:(void(^)(NSError *error))fail;
    
    
    
    @end
    #import "JMHttpRequestMethod.h"
    #import "YTKKeyValueStore.h"
    
    #define PATH_OF_NetWork    [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0]
    
    typedef NS_ENUM(NSUInteger, JMNetworkStatus) {
        JMNetworkStatusUnknown,  //未知的网络
        JMNetworkStatusNotNetWork, //没有网络
        JMNetworkStatusReachableViaWWAN,//手机蜂窝数据网络
        JMNetworkStatusReachableViaWiFi //WIFI 网络
    };
    
    
    @interface JMHttpRequestMethod ()
    @end
    
    @implementation JMHttpRequestMethod
    
    static NSString *const  httpCache = @"NetworkCache";
    static YTKKeyValueStore *_store;
    static JMNetworkStatus _status;
    static BOOL    _isHasNetWork;
    
    + (void)load
    {
        JMHttpRequestMethod *httpMethod;
        httpMethod.requestSerializer = [AFJSONRequestSerializer serializer];
        //设置请求的超时时间
        httpMethod.requestSerializer.timeoutInterval = 20.f;
        //设置服务器返回结果的类型:JSON (AFJSONResponseSerializer,AFHTTPResponseSerializer)
        httpMethod.responseSerializer = [AFJSONResponseSerializer serializer];
        
        httpMethod.responseSerializer.acceptableContentTypes = [NSSet setWithObjects:
                                                                @"application/json",
                                                                @"text/html",
                                                                @"text/json",
                                                                @"text/plain",
                                                                @"text/javascript",
                                                                @"text/xml", @"image/*", nil];
          [self startMonitoringNetworkStatus];
    }
    
    /**
     监测网络状态 (在程序入口,调用一次即可)
     */
    + (void)startMonitoringNetworkStatus
    {
            AFNetworkReachabilityManager *manager = [AFNetworkReachabilityManager sharedManager];
            [manager setReachabilityStatusChangeBlock:^(AFNetworkReachabilityStatus status) {
                switch (status)
                {
                    case AFNetworkReachabilityStatusUnknown:
                        _isHasNetWork = NO;
                        _status = JMNetworkStatusUnknown;
                        break;
                    case AFNetworkReachabilityStatusNotReachable:
                        _isHasNetWork = NO;
                        _status = JMNetworkStatusNotNetWork;
                        NSLog(@"没有网的状态");
                        break;
                    case AFNetworkReachabilityStatusReachableViaWWAN:
                        _isHasNetWork = YES;
                        _status = JMNetworkStatusReachableViaWWAN;
                        break;
                    case AFNetworkReachabilityStatusReachableViaWiFi:
                        _isHasNetWork = YES;
                        _status = JMNetworkStatusReachableViaWiFi;
                        NSLog(@"现在是有网状态");
                        break;
                }
            }];
            [manager startMonitoring];
    }
    /**
     设置 请求和响应类型和超时时间
     
     @param requestType  默认为请求类型为JSON格式
     @param responseType 默认响应格式为JSON格式
     @param timeOut      请求超时时间 默认为20秒
     */
    +(void)setTimeOutWithTime:(NSTimeInterval)timeOut
                  requestType:(JMRequestSerializer)requestType
                 responseType:(JMResponseSerializer)responseType
    {
        
        JMHttpRequestMethod *httpMethod;
        httpMethod.requestSerializer.timeoutInterval = timeOut;
        switch (requestType) {
            case JMRequestSerializerJSON:
                httpMethod.requestSerializer = [AFJSONRequestSerializer serializer];
                break;
            case JMRequestSerializerPlainText:
                httpMethod.requestSerializer = [AFHTTPRequestSerializer serializer];
                break;
            default:
                break;
        }
        switch (responseType) {
            case JMResponseSerializerJSON:
                httpMethod.responseSerializer = [AFJSONResponseSerializer serializer];
                break;
                case JMResponseSerializerHTTP:
                httpMethod.responseSerializer = [AFHTTPResponseSerializer serializer];
                break;
                case JMResponseSerializerXML:
                httpMethod.responseSerializer = [AFXMLParserResponseSerializer serializer];
            default:
                break;
        }
    }
    /**
     设置 请求头
     
     @param httpBody 根据服务器要求 配置相应的请求体
     */
    + (void)setHttpBodyWithDic:(NSDictionary *)httpBody
    {
        JMHttpRequestMethod *httpMethod;
        for (NSString *key in httpBody.allKeys) {
            if (httpBody[key] != nil) {
                [httpMethod.requestSerializer setValue:httpBody[key] forHTTPHeaderField:key];
            }
        }
    }
    
    
    /**
     获取当前的网络状态
     
     @return YES 有网  NO 没有联网
     */
    +(BOOL)getCurrentNetWorkStatus
    {
        return _isHasNetWork;
    }
    
    /**
     获取网络缓存 文件大小
     
     @return size  单位M
     */
    + (NSString *)fileSizeWithDBPath
    {
        NSFileManager* manager = [NSFileManager defaultManager];
        if ([manager fileExistsAtPath:[PATH_OF_NetWork stringByAppendingPathComponent:httpCache]]){
            unsigned  long long  fileSize =  [[manager attributesOfItemAtPath:[PATH_OF_NetWork stringByAppendingPathComponent:httpCache] error:nil] fileSize];
            NSString *size = [NSString stringWithFormat:@"%.2fM",fileSize/1024.0/1024.0];
            return  size;
        }else {
            return @"0M";
        }
        return 0;
    }
    
    /**
     清除所有网络缓存
     */
    + (void)cleanNetWorkRefreshCache
    {
        NSError *error;
        BOOL isSuccess =  [[NSFileManager defaultManager]removeItemAtPath:[PATH_OF_NetWork stringByAppendingPathComponent:httpCache] error:&error];
        if (isSuccess) {
            NSLog(@"clean cache file is success");
        }else {
            if ([PATH_OF_NetWork stringByAppendingPathComponent:httpCache]) {
                   NSLog(@"error:%@",error.description);
            }else {
                NSLog(@"error: cache file is not exist");
            }
         
        }
    }
    
    #pragma mark -  /**************GET 请求API ******************/
    
    + (JMHttpRequestMethod *)getWithUrl:(NSString *)url
                           refreshCache:(BOOL)refreshCache
                                success:(void(^)(id responseObject))success
                                   fail:(void(^)(NSError *error))fail
    {
        return [self getWithUrl:url refreshCache:refreshCache params:nil success:success fail:fail];
    }
    // 多一个params参数
    + (JMHttpRequestMethod *)getWithUrl:(NSString *)url
                           refreshCache:(BOOL)refreshCache
                                 params:(NSDictionary *)params
                                success:(void(^)(id responseObject))success
                                   fail:(void(^)(NSError *error))fail
    {
        return [self getWithUrl:url refreshCache:refreshCache params:params progress:nil success:success fail:fail];
    }
    // 多一个带进度回调
    + (JMHttpRequestMethod *)getWithUrl:(NSString *)url
                           refreshCache:(BOOL)refreshCache
                                 params:(NSDictionary *)params
                               progress:(void(^)(int64_t bytesRead, int64_t totalBytesRead))progress
                                success:(void(^)(id responseObject))success
                                   fail:(void(^)(NSError *error))fail
    {
        _store = [[YTKKeyValueStore alloc] initDBWithName:httpCache];
        [_store createTableWithName:httpCache];
        JMHttpRequestMethod *request = nil;
        if ([JMHttpRequestMethod getCurrentNetWorkStatus]) {
            if (!refreshCache) {
                [self requestNotCacheWithHttpMethod:0 url:url params:params progress:progress success:success fail:fail];
            }else {
                NSDictionary *dict =   [_store getObjectById:url  fromTable:httpCache];
                if (dict) {
                    success(dict);
                }else {
                    [[self manager] GET:url parameters:params progress:^(NSProgress * _Nonnull downloadProgress) {
                        progress(downloadProgress.completedUnitCount, downloadProgress.totalUnitCount);
                    } success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
                        [_store putObject:responseObject withId:url intoTable:httpCache];
                        success(responseObject);
                        NSLog(@"
    Request success, URL: %@
     params:%@
     response:%@
    
    ",url,params,responseObject);
                    } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
                        fail(error);
                        NSLog(@"error = %@",error.description);
                    }];
                }
            }
        } else {
            NSDictionary *dict =   [_store getObjectById:url  fromTable:httpCache];
            if (dict) {
                success(dict);
            }else {
                NSLog(@"当前为无网络状态,本地也没有缓存数据");
            }
        }
        return request;
    }
    #pragma mark - /*********************** POST 请求API **********************/ + (JMHttpRequestMethod *)postWithUrl:(NSString *)url refreshCache:(BOOL)refreshCache params:(NSDictionary *)params success:(void(^)(id responseObject))success fail:(void(^)(NSError *error))fail { return [self postWithUrl:url refreshCache:refreshCache params:params progress:nil success:success fail:fail]; } + (JMHttpRequestMethod *)postWithUrl:(NSString *)url refreshCache:(BOOL)refreshCache params:(NSDictionary *)params progress:(void(^)(int64_t bytesRead, int64_t totalBytesRead))progress success:(void(^)(id responseObject))success fail:(void(^)(NSError *error))fail { JMHttpRequestMethod *request = nil; if ([JMHttpRequestMethod getCurrentNetWorkStatus]) { if (!refreshCache) { [self requestNotCacheWithHttpMethod:1 url:url params:params progress:progress success:success fail:fail]; }else { NSDictionary *dict = [_store getObjectById:url fromTable:httpCache]; if (dict) { success(dict); }else { [[self manager] POST:url parameters:params progress:^(NSProgress * _Nonnull downloadProgress) { progress(downloadProgress.completedUnitCount, downloadProgress.totalUnitCount); } success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) { [_store putObject:responseObject withId:url intoTable:httpCache]; success(responseObject); NSLog(@" Request success, URL: %@ params:%@ response:%@ ",url,params,responseObject); } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) { fail(error); }]; } } } else { NSDictionary *dict = [_store getObjectById:url fromTable:httpCache]; if (dict) { success(dict); }else { NSLog(@"当前为无网络状态,本地也没有缓存数据"); } } return request; } + (void)requestNotCacheWithHttpMethod:(NSInteger)httpMethod url:(NSString *)url params:(NSDictionary *)params progress:(void(^)(int64_t bytesRead, int64_t totalBytesRead))progress success:(void(^)(id responseObject))success fail:(void(^)(NSError *error))fail { if (httpMethod == 0) { [[self manager]GET:url parameters:params progress:^(NSProgress * _Nonnull downloadProgress) { progress(downloadProgress.completedUnitCount, downloadProgress.totalUnitCount); } success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) { success(responseObject); NSLog(@" Request success, URL: %@ params:%@ response:%@ ",url,params,responseObject); } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) { fail(error); }]; }else { [[self manager ]POST:url parameters:params progress:^(NSProgress * _Nonnull uploadProgress) { progress(uploadProgress.completedUnitCount, uploadProgress.totalUnitCount); } success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) { success(responseObject); NSLog(@" Request success, URL: %@ params:%@ response:%@ ",url,params,responseObject); } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) { fail(error); }]; } } @end

    2.数据缓存(FMDB)

    #import <Foundation/Foundation.h>
    
    @interface YTKKeyValueItem : NSObject
    
    @property (strong, nonatomic) NSString *itemId;
    @property (strong, nonatomic) id itemObject;
    @property (strong, nonatomic) NSDate *createdTime;
    
    @end
    
    
    @interface YTKKeyValueStore : NSObject
    
    - (id)initDBWithName:(NSString *)dbName;
    
    - (id)initWithDBWithPath:(NSString *)dbPath;
    
    - (void)createTableWithName:(NSString *)tableName;
    
    - (void)clearTable:(NSString *)tableName;
    
    - (void)close;
    
    ///************************ Put&Get methods *****************************************
    
    - (void)putObject:(id)object withId:(NSString *)objectId intoTable:(NSString *)tableName;
    
    - (id)getObjectById:(NSString *)objectId fromTable:(NSString *)tableName;
    
    - (YTKKeyValueItem *)getYTKKeyValueItemById:(NSString *)objectId fromTable:(NSString *)tableName;
    
    - (void)putString:(NSString *)string withId:(NSString *)stringId intoTable:(NSString *)tableName;
    
    - (NSString *)getStringById:(NSString *)stringId fromTable:(NSString *)tableName;
    
    - (void)putNumber:(NSNumber *)number withId:(NSString *)numberId intoTable:(NSString *)tableName;
    
    - (NSNumber *)getNumberById:(NSString *)numberId fromTable:(NSString *)tableName;
    
    - (NSArray *)getAllItemsFromTable:(NSString *)tableName;
    
    - (void)deleteObjectById:(NSString *)objectId fromTable:(NSString *)tableName;
    
    - (void)deleteObjectsByIdArray:(NSArray *)objectIdArray fromTable:(NSString *)tableName;
    
    - (void)deleteObjectsByIdPrefix:(NSString *)objectIdPrefix fromTable:(NSString *)tableName;
    
    
    @end
    #import "YTKKeyValueStore.h"
    #import "FMDatabase.h"
    #import "FMDatabaseQueue.h"
    
    #ifdef DEBUG
    #define debugLog(s, ...) NSLog( @"[%@ in line %d] ➡️➡️➡️%@", [[NSString stringWithUTF8String:__FILE__] lastPathComponent], __LINE__, [NSString stringWithFormat:(s), ##__VA_ARGS__] )
    #define debugMethod()    NSLog(@"%s", __func__)
    #define debugError(s, ...)     NSLog( @"[%@ in line %d] ➡️➡️➡️%@", [[NSString stringWithUTF8String:__FILE__] lastPathComponent], __LINE__, [NSString stringWithFormat:(s), ##__VA_ARGS__] )
    #else
    #define debugLog(s,...)
    #define debugMethod()
    #define debugError(s, ...)
    #endif
    
    #define PATH_OF_DOCUMENT    [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0]
    
    @implementation YTKKeyValueItem
    
    - (NSString *)description {
        return [NSString stringWithFormat:@"id=%@, value=%@, timeStamp=%@", _itemId, _itemObject, _createdTime];
    }
    
    @end
    
    @interface YTKKeyValueStore()
    
    @property (strong, nonatomic) FMDatabaseQueue * dbQueue;
    
    @end
    
    @implementation YTKKeyValueStore
    
    static NSString *const DEFAULT_DB_NAME = @"database.sqlite";
    
    static NSString *const CREATE_TABLE_SQL =
    @"CREATE TABLE IF NOT EXISTS %@ ( 
    id TEXT NOT NULL, 
    json TEXT NOT NULL, 
    createdTime TEXT NOT NULL, 
    PRIMARY KEY(id)) 
    ";
    
    static NSString *const UPDATE_ITEM_SQL = @"REPLACE INTO %@ (id, json, createdTime) values (?, ?, ?)";
    
    static NSString *const QUERY_ITEM_SQL = @"SELECT json, createdTime from %@ where id = ? Limit 1";
    
    static NSString *const SELECT_ALL_SQL = @"SELECT * from %@";
    
    static NSString *const CLEAR_ALL_SQL = @"DELETE from %@";
    
    static NSString *const DELETE_ITEM_SQL = @"DELETE from %@ where id = ?";
    
    static NSString *const DELETE_ITEMS_SQL = @"DELETE from %@ where id in ( %@ )";
    
    static NSString *const DELETE_ITEMS_WITH_PREFIX_SQL = @"DELETE from %@ where id like ? ";
    
    + (BOOL)checkTableName:(NSString *)tableName {
        if (tableName == nil || tableName.length == 0 || [tableName rangeOfString:@" "].location != NSNotFound) {
            debugLog(@"ERROR, table name: %@ format error.", tableName);
            return NO;
        }
        return YES;
    }
    
    - (id)init {
        return [self initDBWithName:DEFAULT_DB_NAME];
    }
    
    - (id)initDBWithName:(NSString *)dbName {
        self = [super init];
        if (self) {
            NSString * dbPath = [PATH_OF_DOCUMENT stringByAppendingPathComponent:dbName];
            debugLog(@"dbPath = %@", dbPath);
            if (_dbQueue) {
                [self close];
            }
            _dbQueue = [FMDatabaseQueue databaseQueueWithPath:dbPath];
        }
        return self;
    }
    
    - (id)initWithDBWithPath:(NSString *)dbPath {
        self = [super init];
        if (self) {
            debugLog(@"dbPath = %@", dbPath);
            if (_dbQueue) {
                [self close];
            }
            _dbQueue = [FMDatabaseQueue databaseQueueWithPath:dbPath];
        }
        return self;
    }
    
    - (void)createTableWithName:(NSString *)tableName {
        if ([YTKKeyValueStore checkTableName:tableName] == NO) {
            return;
        }
        NSString * sql = [NSString stringWithFormat:CREATE_TABLE_SQL, tableName];
        __block BOOL result;
        [_dbQueue inDatabase:^(FMDatabase *db) {
            result = [db executeUpdate:sql];
        }];
        if (!result) {
            debugLog(@"ERROR, failed to create table: %@", tableName);
        }
    }
    
    - (void)clearTable:(NSString *)tableName {
        if ([YTKKeyValueStore checkTableName:tableName] == NO) {
            return;
        }
        NSString * sql = [NSString stringWithFormat:CLEAR_ALL_SQL, tableName];
        __block BOOL result;
        [_dbQueue inDatabase:^(FMDatabase *db) {
            result = [db executeUpdate:sql];
        }];
        if (!result) {
            debugLog(@"ERROR, failed to clear table: %@", tableName);
        }
    }
    
    - (void)putObject:(id)object withId:(NSString *)objectId intoTable:(NSString *)tableName {
        if ([YTKKeyValueStore checkTableName:tableName] == NO) {
            return;
        }
        NSError * error;
        NSData * data = [NSJSONSerialization dataWithJSONObject:object options:0 error:&error];
        if (error) {
            debugLog(@"ERROR, faild to get json data");
            return;
        }
        NSString * jsonString = [[NSString alloc] initWithData:data encoding:(NSUTF8StringEncoding)];
        NSDate * createdTime = [NSDate date];
        NSString * sql = [NSString stringWithFormat:UPDATE_ITEM_SQL, tableName];
        __block BOOL result;
        [_dbQueue inDatabase:^(FMDatabase *db) {
            result = [db executeUpdate:sql, objectId, jsonString, createdTime];
        }];
        if (!result) {
            debugLog(@"ERROR, failed to insert/replace into table: %@", tableName);
        }
    }
    
    - (id)getObjectById:(NSString *)objectId fromTable:(NSString *)tableName {
        YTKKeyValueItem * item = [self getYTKKeyValueItemById:objectId fromTable:tableName];
        if (item) {
            return item.itemObject;
        } else {
            return nil;
        }
    }
    
    - (YTKKeyValueItem *)getYTKKeyValueItemById:(NSString *)objectId fromTable:(NSString *)tableName {
        if ([YTKKeyValueStore checkTableName:tableName] == NO) {
            return nil;
        }
        NSString * sql = [NSString stringWithFormat:QUERY_ITEM_SQL, tableName];
        __block NSString * json = nil;
        __block NSDate * createdTime = nil;
        [_dbQueue inDatabase:^(FMDatabase *db) {
            FMResultSet * rs = [db executeQuery:sql, objectId];
            if ([rs next]) {
                json = [rs stringForColumn:@"json"];
                createdTime = [rs dateForColumn:@"createdTime"];
            }
            [rs close];
        }];
        if (json) {
            NSError * error;
            id result = [NSJSONSerialization JSONObjectWithData:[json dataUsingEncoding:NSUTF8StringEncoding]
                                                        options:(NSJSONReadingAllowFragments) error:&error];
            if (error) {
                debugLog(@"ERROR, faild to prase to json");
                return nil;
            }
            YTKKeyValueItem * item = [[YTKKeyValueItem alloc] init];
            item.itemId = objectId;
            item.itemObject = result;
            item.createdTime = createdTime;
            return item;
        } else {
            return nil;
        }
    }
    
    - (void)putString:(NSString *)string withId:(NSString *)stringId intoTable:(NSString *)tableName {
        if (string == nil) {
            debugLog(@"error, string is nil");
            return;
        }
        [self putObject:@[string] withId:stringId intoTable:tableName];
    }
    
    - (NSString *)getStringById:(NSString *)stringId fromTable:(NSString *)tableName {
        NSArray * array = [self getObjectById:stringId fromTable:tableName];
        if (array && [array isKindOfClass:[NSArray class]]) {
            return array[0];
        }
        return nil;
    }
    
    - (void)putNumber:(NSNumber *)number withId:(NSString *)numberId intoTable:(NSString *)tableName {
        if (number == nil) {
            debugLog(@"error, number is nil");
            return;
        }
        [self putObject:@[number] withId:numberId intoTable:tableName];
    }
    
    - (NSNumber *)getNumberById:(NSString *)numberId fromTable:(NSString *)tableName {
        NSArray * array = [self getObjectById:numberId fromTable:tableName];
        if (array && [array isKindOfClass:[NSArray class]]) {
            return array[0];
        }
        return nil;
    }
    
    - (NSArray *)getAllItemsFromTable:(NSString *)tableName {
        if ([YTKKeyValueStore checkTableName:tableName] == NO) {
            return nil;
        }
        NSString * sql = [NSString stringWithFormat:SELECT_ALL_SQL, tableName];
        __block NSMutableArray * result = [NSMutableArray array];
        [_dbQueue inDatabase:^(FMDatabase *db) {
            FMResultSet * rs = [db executeQuery:sql];
            while ([rs next]) {
                YTKKeyValueItem * item = [[YTKKeyValueItem alloc] init];
                item.itemId = [rs stringForColumn:@"id"];
                item.itemObject = [rs stringForColumn:@"json"];
                item.createdTime = [rs dateForColumn:@"createdTime"];
                [result addObject:item];
            }
            [rs close];
        }];
        // parse json string to object
        NSError * error;
        for (YTKKeyValueItem * item in result) {
            error = nil;
            id object = [NSJSONSerialization JSONObjectWithData:[item.itemObject dataUsingEncoding:NSUTF8StringEncoding]
                                                        options:(NSJSONReadingAllowFragments) error:&error];
            if (error) {
                debugLog(@"ERROR, faild to prase to json.");
            } else {
                item.itemObject = object;
            }
        }
        return result;
    }
    
    - (void)deleteObjectById:(NSString *)objectId fromTable:(NSString *)tableName {
        if ([YTKKeyValueStore checkTableName:tableName] == NO) {
            return;
        }
        NSString * sql = [NSString stringWithFormat:DELETE_ITEM_SQL, tableName];
        __block BOOL result;
        [_dbQueue inDatabase:^(FMDatabase *db) {
            result = [db executeUpdate:sql, objectId];
        }];
        if (!result) {
            debugLog(@"ERROR, failed to delete item from table: %@", tableName);
        }
    }
    
    - (void)deleteObjectsByIdArray:(NSArray *)objectIdArray fromTable:(NSString *)tableName {
        if ([YTKKeyValueStore checkTableName:tableName] == NO) {
            return;
        }
        NSMutableString *stringBuilder = [NSMutableString string];
        for (id objectId in objectIdArray) {
            NSString *item = [NSString stringWithFormat:@" '%@' ", objectId];
            if (stringBuilder.length == 0) {
                [stringBuilder appendString:item];
            } else {
                [stringBuilder appendString:@","];
                [stringBuilder appendString:item];
            }
        }
        NSString *sql = [NSString stringWithFormat:DELETE_ITEMS_SQL, tableName, stringBuilder];
        __block BOOL result;
        [_dbQueue inDatabase:^(FMDatabase *db) {
            result = [db executeUpdate:sql];
        }];
        if (!result) {
            debugLog(@"ERROR, failed to delete items by ids from table: %@", tableName);
        }
    }
    
    - (void)deleteObjectsByIdPrefix:(NSString *)objectIdPrefix fromTable:(NSString *)tableName {
        if ([YTKKeyValueStore checkTableName:tableName] == NO) {
            return;
        }
        NSString *sql = [NSString stringWithFormat:DELETE_ITEMS_WITH_PREFIX_SQL, tableName];
        NSString *prefixArgument = [NSString stringWithFormat:@"%@%%", objectIdPrefix];
        __block BOOL result;
        [_dbQueue inDatabase:^(FMDatabase *db) {
            result = [db executeUpdate:sql, prefixArgument];
        }];
        if (!result) {
            debugLog(@"ERROR, failed to delete items by id prefix from table: %@", tableName);
        }
    }
    
    - (void)close {
        [_dbQueue close];
        _dbQueue = nil;
    }
    
    @end

    3.使用示例

    [JMHttpRequestMethod getWithUrl:url1 refreshCache:YES success:^(id responseObject) {
           
            NSData *jsonData = [NSJSONSerialization dataWithJSONObject:responseObject options:NSJSONWritingPrettyPrinted error:nil];
            self.textView.text = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
    
           // [JMHttpRequestMethod cleanNetWorkRefreshCache];
             NSLog(@"缓存大小为%@",  [JMHttpRequestMethod fileSizeWithDBPath]);
        } fail:^(NSError *error) {
            
        }];

    第二种实现方式:

      功能:POST GET Upload download

    #import "HYBNetworking.h"
    #import "AFNetworkActivityIndicatorManager.h"
    #import "AFNetworking.h"
    #import "AFHTTPSessionManager.h"
    
    #import <CommonCrypto/CommonDigest.h>
    
    @interface NSString (md5)
    
    + (NSString *)hybnetworking_md5:(NSString *)string;
    
    @end
    
    @implementation NSString (md5)
    
    + (NSString *)hybnetworking_md5:(NSString *)string {
      if (string == nil || [string length] == 0) {
        return nil;
      }
      
      unsigned char digest[CC_MD5_DIGEST_LENGTH], i;
      CC_MD5([string UTF8String], (int)[string lengthOfBytesUsingEncoding:NSUTF8StringEncoding], digest);
      NSMutableString *ms = [NSMutableString string];
      
      for (i = 0; i < CC_MD5_DIGEST_LENGTH; i++) {
        [ms appendFormat:@"%02x", (int)(digest[i])];
      }
      
      return [ms copy];
    }
    
    @end
    
    static NSString *sg_privateNetworkBaseUrl = nil;
    static BOOL sg_isEnableInterfaceDebug = NO;
    static BOOL sg_shouldAutoEncode = NO;
    static NSDictionary *sg_httpHeaders = nil;
    static HYBResponseType sg_responseType = kHYBResponseTypeJSON;
    static HYBRequestType  sg_requestType  = kHYBRequestTypePlainText;
    static HYBNetworkStatus sg_networkStatus = kHYBNetworkStatusReachableViaWiFi;
    static NSMutableArray *sg_requestTasks;
    static BOOL sg_cacheGet = YES;
    static BOOL sg_cachePost = NO;
    static BOOL sg_shouldCallbackOnCancelRequest = YES;
    static NSTimeInterval sg_timeout = 60.0f;
    static BOOL sg_shoulObtainLocalWhenUnconnected = NO;
    static BOOL sg_isBaseURLChanged = YES;
    static AFHTTPSessionManager *sg_sharedManager = nil;
    static NSUInteger sg_maxCacheSize = 0;
    
    @implementation HYBNetworking
    
    + (void)load {
      static dispatch_once_t onceToken;
      dispatch_once(&onceToken, ^{
        // 尝试清除缓存
        if (sg_maxCacheSize > 0 && [self totalCacheSize] > 1024 * 1024 * sg_maxCacheSize) {
          [self clearCaches];
        }
      });
    }
    
    + (void)autoToClearCacheWithLimitedToSize:(NSUInteger)mSize {
      sg_maxCacheSize = mSize;
    }
    
    + (void)cacheGetRequest:(BOOL)isCacheGet shoulCachePost:(BOOL)shouldCachePost {
      sg_cacheGet = isCacheGet;
      sg_cachePost = shouldCachePost;
    }
    
    + (void)updateBaseUrl:(NSString *)baseUrl {
      if (![baseUrl isEqualToString:sg_privateNetworkBaseUrl] && baseUrl && baseUrl.length) {
        sg_isBaseURLChanged = YES;
      } else {
        sg_isBaseURLChanged = NO;
      }
      
      sg_privateNetworkBaseUrl = baseUrl;
    }
    
    + (NSString *)baseUrl {
      return sg_privateNetworkBaseUrl;
    }
    
    + (void)setTimeout:(NSTimeInterval)timeout {
      sg_timeout = timeout;
    }
    
    + (void)obtainDataFromLocalWhenNetworkUnconnected:(BOOL)shouldObtain {
      sg_shoulObtainLocalWhenUnconnected = shouldObtain;
      if (sg_shoulObtainLocalWhenUnconnected && (sg_cacheGet || sg_cachePost)) {
        [self detectNetwork];
      }
    }
    
    + (void)enableInterfaceDebug:(BOOL)isDebug {
      sg_isEnableInterfaceDebug = isDebug;
    }
    
    + (BOOL)isDebug {
      return sg_isEnableInterfaceDebug;
    }
    
    static inline NSString *cachePath() {
      return [NSHomeDirectory() stringByAppendingPathComponent:@"Documents/HYBNetworkingCaches"];
    }
    
    + (void)clearCaches {
      NSString *directoryPath = cachePath();
      
      if ([[NSFileManager defaultManager] fileExistsAtPath:directoryPath isDirectory:nil]) {
        NSError *error = nil;
        [[NSFileManager defaultManager] removeItemAtPath:directoryPath error:&error];
        
        if (error) {
          NSLog(@"HYBNetworking clear caches error: %@", error);
        } else {
          NSLog(@"HYBNetworking clear caches ok");
        }
      }
    }
    
    + (unsigned long long)totalCacheSize {
      NSString *directoryPath = cachePath();
      BOOL isDir = NO;
      unsigned long long total = 0;
      
      if ([[NSFileManager defaultManager] fileExistsAtPath:directoryPath isDirectory:&isDir]) {
        if (isDir) {
          NSError *error = nil;
          NSArray *array = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:directoryPath error:&error];
          
          if (error == nil) {
            for (NSString *subpath in array) {
              NSString *path = [directoryPath stringByAppendingPathComponent:subpath];
              NSDictionary *dict = [[NSFileManager defaultManager] attributesOfItemAtPath:path
                                                                                    error:&error];
              if (!error) {
                total += [dict[NSFileSize] unsignedIntegerValue];
              }
            }
          }
        }
      }
      
      return total;
    }
    
    + (NSMutableArray *)allTasks {
      static dispatch_once_t onceToken;
      dispatch_once(&onceToken, ^{
        if (sg_requestTasks == nil) {
          sg_requestTasks = [[NSMutableArray alloc] init];
        }
      });
      
      return sg_requestTasks;
    }
    
    + (void)cancelAllRequest {
      @synchronized(self) {
        [[self allTasks] enumerateObjectsUsingBlock:^(HYBURLSessionTask * _Nonnull task, NSUInteger idx, BOOL * _Nonnull stop) {
          if ([task isKindOfClass:[HYBURLSessionTask class]]) {
            [task cancel];
          }
        }];
        
        [[self allTasks] removeAllObjects];
      };
    }
    
    + (void)cancelRequestWithURL:(NSString *)url {
      if (url == nil) {
        return;
      }
      
      @synchronized(self) {
        [[self allTasks] enumerateObjectsUsingBlock:^(HYBURLSessionTask * _Nonnull task, NSUInteger idx, BOOL * _Nonnull stop) {
          if ([task isKindOfClass:[HYBURLSessionTask class]]
              && [task.currentRequest.URL.absoluteString hasSuffix:url]) {
            [task cancel];
            [[self allTasks] removeObject:task];
            return;
          }
        }];
      };
    }
    
    + (void)configRequestType:(HYBRequestType)requestType
                 responseType:(HYBResponseType)responseType
          shouldAutoEncodeUrl:(BOOL)shouldAutoEncode
      callbackOnCancelRequest:(BOOL)shouldCallbackOnCancelRequest {
      sg_requestType = requestType;
      sg_responseType = responseType;
      sg_shouldAutoEncode = shouldAutoEncode;
      sg_shouldCallbackOnCancelRequest = shouldCallbackOnCancelRequest;
    }
    
    + (BOOL)shouldEncode {
      return sg_shouldAutoEncode;
    }
    
    + (void)configCommonHttpHeaders:(NSDictionary *)httpHeaders {
      sg_httpHeaders = httpHeaders;
    }
    
    + (HYBURLSessionTask *)getWithUrl:(NSString *)url
                         refreshCache:(BOOL)refreshCache
                              success:(HYBResponseSuccess)success
                                 fail:(HYBResponseFail)fail {
      return [self getWithUrl:url
                 refreshCache:refreshCache
                       params:nil
                      success:success
                         fail:fail];
    }
    
    + (HYBURLSessionTask *)getWithUrl:(NSString *)url
                         refreshCache:(BOOL)refreshCache
                               params:(NSDictionary *)params
                              success:(HYBResponseSuccess)success
                                 fail:(HYBResponseFail)fail {
      return [self getWithUrl:url
                 refreshCache:refreshCache
                       params:params
                     progress:nil
                      success:success
                         fail:fail];
    }
    
    + (HYBURLSessionTask *)getWithUrl:(NSString *)url
                         refreshCache:(BOOL)refreshCache
                               params:(NSDictionary *)params
                             progress:(HYBGetProgress)progress
                              success:(HYBResponseSuccess)success
                                 fail:(HYBResponseFail)fail {
      return [self _requestWithUrl:url
                      refreshCache:refreshCache
                         httpMedth:1
                            params:params
                          progress:progress
                           success:success
                              fail:fail];
    }
    
    + (HYBURLSessionTask *)postWithUrl:(NSString *)url
                          refreshCache:(BOOL)refreshCache
                                params:(NSDictionary *)params
                               success:(HYBResponseSuccess)success
                                  fail:(HYBResponseFail)fail {
      return [self postWithUrl:url
                  refreshCache:refreshCache
                        params:params
                      progress:nil
                       success:success
                          fail:fail];
    }
    
    + (HYBURLSessionTask *)postWithUrl:(NSString *)url
                          refreshCache:(BOOL)refreshCache
                                params:(NSDictionary *)params
                              progress:(HYBPostProgress)progress
                               success:(HYBResponseSuccess)success
                                  fail:(HYBResponseFail)fail {
      return [self _requestWithUrl:url
                      refreshCache:refreshCache
                         httpMedth:2
                            params:params
                          progress:progress
                           success:success
                              fail:fail];
    }
    
    + (HYBURLSessionTask *)_requestWithUrl:(NSString *)url
                              refreshCache:(BOOL)refreshCache
                                 httpMedth:(NSUInteger)httpMethod
                                    params:(NSDictionary *)params
                                  progress:(HYBDownloadProgress)progress
                                   success:(HYBResponseSuccess)success
                                      fail:(HYBResponseFail)fail {
      if ([self shouldEncode]) {
        url = [self encodeUrl:url];
      }
    
      AFHTTPSessionManager *manager = [self manager];
      NSString *absolute = [self absoluteUrlWithPath:url];
      
      if ([self baseUrl] == nil) {
        if ([NSURL URLWithString:url] == nil) {
          HYBAppLog(@"URLString无效,无法生成URL。可能是URL中有中文,请尝试Encode URL");
          return nil;
        }
      } else {
        NSURL *absoluteURL = [NSURL URLWithString:absolute];
        
        if (absoluteURL == nil) {
          HYBAppLog(@"URLString无效,无法生成URL。可能是URL中有中文,请尝试Encode URL");
          return nil;
        }
      }
      
      HYBURLSessionTask *session = nil;
      
      if (httpMethod == 1) {
        if (sg_cacheGet) {
          if (sg_shoulObtainLocalWhenUnconnected) {
            if (sg_networkStatus == kHYBNetworkStatusNotReachable ||  sg_networkStatus == kHYBNetworkStatusUnknown ) {
              id response = [HYBNetworking cahceResponseWithURL:absolute
                                                     parameters:params];
              if (response) {
                if (success) {
                  [self successResponse:response callback:success];
                  
                  if ([self isDebug]) {
                    [self logWithSuccessResponse:response
                                             url:absolute
                                          params:params];
                  }
                }
                return nil;
              }
            }
          }
          if (!refreshCache) {// 获取缓存
            id response = [HYBNetworking cahceResponseWithURL:absolute
                                                   parameters:params];
            if (response) {
              if (success) {
                [self successResponse:response callback:success];
                
                if ([self isDebug]) {
                  [self logWithSuccessResponse:response
                                           url:absolute
                                        params:params];
                }
              }
              return nil;
            }
          }
        }
        
        session = [manager GET:url parameters:params progress:^(NSProgress * _Nonnull downloadProgress) {
          if (progress) {
            progress(downloadProgress.completedUnitCount, downloadProgress.totalUnitCount);
          }
        } success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
          [self successResponse:responseObject callback:success];
          
          if (sg_cacheGet) {
            [self cacheResponseObject:responseObject request:task.currentRequest parameters:params];
          }
          
          [[self allTasks] removeObject:task];
          
          if ([self isDebug]) {
            [self logWithSuccessResponse:responseObject
                                     url:absolute
                                  params:params];
          }
        } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
          [[self allTasks] removeObject:task];
          
          if ([error code] < 0 && sg_cacheGet) {// 获取缓存
            id response = [HYBNetworking cahceResponseWithURL:absolute
                                                   parameters:params];
            if (response) {
              if (success) {
                [self successResponse:response callback:success];
                
                if ([self isDebug]) {
                  [self logWithSuccessResponse:response
                                           url:absolute
                                        params:params];
                }
              }
            } else {
              [self handleCallbackWithError:error fail:fail];
              
              if ([self isDebug]) {
                [self logWithFailError:error url:absolute params:params];
              }
            }
          } else {
            [self handleCallbackWithError:error fail:fail];
            
            if ([self isDebug]) {
              [self logWithFailError:error url:absolute params:params];
            }
          }
        }];
      } else if (httpMethod == 2) {
        if (sg_cachePost ) {// 获取缓存
          if (sg_shoulObtainLocalWhenUnconnected) {
            if (sg_networkStatus == kHYBNetworkStatusNotReachable ||  sg_networkStatus == kHYBNetworkStatusUnknown ) {
              id response = [HYBNetworking cahceResponseWithURL:absolute
                                                     parameters:params];
              if (response) {
                if (success) {
                  [self successResponse:response callback:success];
                  
                  if ([self isDebug]) {
                    [self logWithSuccessResponse:response
                                             url:absolute
                                          params:params];
                  }
                }
                return nil;
              }
            }
          }
          if (!refreshCache) {
            id response = [HYBNetworking cahceResponseWithURL:absolute
                                                   parameters:params];
            if (response) {
              if (success) {
                [self successResponse:response callback:success];
                
                if ([self isDebug]) {
                  [self logWithSuccessResponse:response
                                           url:absolute
                                        params:params];
                }
              }
              return nil;
            }
          }
        }
        
        session = [manager POST:url parameters:params progress:^(NSProgress * _Nonnull downloadProgress) {
          if (progress) {
            progress(downloadProgress.completedUnitCount, downloadProgress.totalUnitCount);
          }
        } success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
          [self successResponse:responseObject callback:success];
          
          if (sg_cachePost) {
            [self cacheResponseObject:responseObject request:task.currentRequest  parameters:params];
          }
          
          [[self allTasks] removeObject:task];
          
          if ([self isDebug]) {
            [self logWithSuccessResponse:responseObject
                                     url:absolute
                                  params:params];
          }
        } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
          [[self allTasks] removeObject:task];
          
          if ([error code] < 0 && sg_cachePost) {// 获取缓存
            id response = [HYBNetworking cahceResponseWithURL:absolute
                                                   parameters:params];
            
            if (response) {
              if (success) {
                [self successResponse:response callback:success];
                
                if ([self isDebug]) {
                  [self logWithSuccessResponse:response
                                           url:absolute
                                        params:params];
                }
              }
            } else {
              [self handleCallbackWithError:error fail:fail];
              
              if ([self isDebug]) {
                [self logWithFailError:error url:absolute params:params];
              }
            }
          } else {
            [self handleCallbackWithError:error fail:fail];
            
            if ([self isDebug]) {
              [self logWithFailError:error url:absolute params:params];
            }
          }
        }];
      }
      
      if (session) {
        [[self allTasks] addObject:session];
      }
      
      return session;
    }
    
    + (HYBURLSessionTask *)uploadFileWithUrl:(NSString *)url
                               uploadingFile:(NSString *)uploadingFile
                                    progress:(HYBUploadProgress)progress
                                     success:(HYBResponseSuccess)success
                                        fail:(HYBResponseFail)fail {
      if ([NSURL URLWithString:uploadingFile] == nil) {
        HYBAppLog(@"uploadingFile无效,无法生成URL。请检查待上传文件是否存在");
        return nil;
      }
      
      NSURL *uploadURL = nil;
      if ([self baseUrl] == nil) {
        uploadURL = [NSURL URLWithString:url];
      } else {
        uploadURL = [NSURL URLWithString:[NSString stringWithFormat:@"%@%@", [self baseUrl], url]];
      }
      
      if (uploadURL == nil) {
        HYBAppLog(@"URLString无效,无法生成URL。可能是URL中有中文或特殊字符,请尝试Encode URL");
        return nil;
      }
      
      AFHTTPSessionManager *manager = [self manager];
      NSURLRequest *request = [NSURLRequest requestWithURL:uploadURL];
      HYBURLSessionTask *session = nil;
      
      [manager uploadTaskWithRequest:request fromFile:[NSURL URLWithString:uploadingFile] progress:^(NSProgress * _Nonnull uploadProgress) {
        if (progress) {
          progress(uploadProgress.completedUnitCount, uploadProgress.totalUnitCount);
        }
      } completionHandler:^(NSURLResponse * _Nonnull response, id  _Nullable responseObject, NSError * _Nullable error) {
        [[self allTasks] removeObject:session];
        
        [self successResponse:responseObject callback:success];
        
        if (error) {
          [self handleCallbackWithError:error fail:fail];
          
          if ([self isDebug]) {
            [self logWithFailError:error url:response.URL.absoluteString params:nil];
          }
        } else {
          if ([self isDebug]) {
            [self logWithSuccessResponse:responseObject
                                     url:response.URL.absoluteString
                                  params:nil];
          }
        }
      }];
      
      if (session) {
        [[self allTasks] addObject:session];
      }
      
      return session;
    }
    
    + (HYBURLSessionTask *)uploadWithImage:(UIImage *)image
                                       url:(NSString *)url
                                  filename:(NSString *)filename
                                      name:(NSString *)name
                                  mimeType:(NSString *)mimeType
                                parameters:(NSDictionary *)parameters
                                  progress:(HYBUploadProgress)progress
                                   success:(HYBResponseSuccess)success
                                      fail:(HYBResponseFail)fail {
      if ([self baseUrl] == nil) {
        if ([NSURL URLWithString:url] == nil) {
          HYBAppLog(@"URLString无效,无法生成URL。可能是URL中有中文,请尝试Encode URL");
          return nil;
        }
      } else {
        if ([NSURL URLWithString:[NSString stringWithFormat:@"%@%@", [self baseUrl], url]] == nil) {
          HYBAppLog(@"URLString无效,无法生成URL。可能是URL中有中文,请尝试Encode URL");
          return nil;
        }
      }
      
      if ([self shouldEncode]) {
        url = [self encodeUrl:url];
      }
      
      NSString *absolute = [self absoluteUrlWithPath:url];
      
      AFHTTPSessionManager *manager = [self manager];
      HYBURLSessionTask *session = [manager POST:url parameters:parameters constructingBodyWithBlock:^(id<AFMultipartFormData>  _Nonnull formData) {
        NSData *imageData = UIImageJPEGRepresentation(image, 1);
        
        NSString *imageFileName = filename;
        if (filename == nil || ![filename isKindOfClass:[NSString class]] || filename.length == 0) {
          NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
          formatter.dateFormat = @"yyyyMMddHHmmss";
          NSString *str = [formatter stringFromDate:[NSDate date]];
          imageFileName = [NSString stringWithFormat:@"%@.jpg", str];
        }
        
        // 上传图片,以文件流的格式
        [formData appendPartWithFileData:imageData name:name fileName:imageFileName mimeType:mimeType];
      } progress:^(NSProgress * _Nonnull uploadProgress) {
        if (progress) {
          progress(uploadProgress.completedUnitCount, uploadProgress.totalUnitCount);
        }
      } success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
        [[self allTasks] removeObject:task];
        [self successResponse:responseObject callback:success];
        
        if ([self isDebug]) {
          [self logWithSuccessResponse:responseObject
                                   url:absolute
                                params:parameters];
        }
      } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
        [[self allTasks] removeObject:task];
        
        [self handleCallbackWithError:error fail:fail];
        
        if ([self isDebug]) {
          [self logWithFailError:error url:absolute params:nil];
        }
      }];
      
      [session resume];
      if (session) {
        [[self allTasks] addObject:session];
      }
      
      return session;
    }
    
    + (HYBURLSessionTask *)downloadWithUrl:(NSString *)url
                                saveToPath:(NSString *)saveToPath
                                  progress:(HYBDownloadProgress)progressBlock
                                   success:(HYBResponseSuccess)success
                                   failure:(HYBResponseFail)failure {
      if ([self baseUrl] == nil) {
        if ([NSURL URLWithString:url] == nil) {
          HYBAppLog(@"URLString无效,无法生成URL。可能是URL中有中文,请尝试Encode URL");
          return nil;
        }
      } else {
        if ([NSURL URLWithString:[NSString stringWithFormat:@"%@%@", [self baseUrl], url]] == nil) {
          HYBAppLog(@"URLString无效,无法生成URL。可能是URL中有中文,请尝试Encode URL");
          return nil;
        }
      }
      
      NSURLRequest *downloadRequest = [NSURLRequest requestWithURL:[NSURL URLWithString:url]];
      AFHTTPSessionManager *manager = [self manager];
      
      HYBURLSessionTask *session = nil;
      
      session = [manager downloadTaskWithRequest:downloadRequest progress:^(NSProgress * _Nonnull downloadProgress) {
        if (progressBlock) {
          progressBlock(downloadProgress.completedUnitCount, downloadProgress.totalUnitCount);
        }
      } destination:^NSURL * _Nonnull(NSURL * _Nonnull targetPath, NSURLResponse * _Nonnull response) {
        return [NSURL fileURLWithPath:saveToPath];
      } completionHandler:^(NSURLResponse * _Nonnull response, NSURL * _Nullable filePath, NSError * _Nullable error) {
        [[self allTasks] removeObject:session];
        
        if (error == nil) {
          if (success) {
            success(filePath.absoluteString);
          }
          
          if ([self isDebug]) {
            HYBAppLog(@"Download success for url %@",
                      [self absoluteUrlWithPath:url]);
          }
        } else {
          [self handleCallbackWithError:error fail:failure];
          
          if ([self isDebug]) {
            HYBAppLog(@"Download fail for url %@, reason : %@",
                      [self absoluteUrlWithPath:url],
                      [error description]);
          }
        }
      }];
      
      [session resume];
      if (session) {
        [[self allTasks] addObject:session];
      }
      
      return session;
    }
    
    #pragma mark - Private
    + (AFHTTPSessionManager *)manager {
      @synchronized (self) {
        // 只要不切换baseurl,就一直使用同一个session manager
        if (sg_sharedManager == nil || sg_isBaseURLChanged) {
          // 开启转圈圈
          [AFNetworkActivityIndicatorManager sharedManager].enabled = YES;
          
          AFHTTPSessionManager *manager = nil;;
          if ([self baseUrl] != nil) {
        #warning session 容易造成循环引用 delegate 是强引用类型 解决方法:1.通过单例的方式创建 2.delloc中释放delegate manager
    = [[AFHTTPSessionManager alloc] initWithBaseURL:[NSURL URLWithString:[self baseUrl]]]; } else { manager = [AFHTTPSessionManager manager]; } switch (sg_requestType) { case kHYBRequestTypeJSON: { manager.requestSerializer = [AFJSONRequestSerializer serializer]; break; } case kHYBRequestTypePlainText: { manager.requestSerializer = [AFHTTPRequestSerializer serializer]; break; } default: { break; } } switch (sg_responseType) { case kHYBResponseTypeJSON: { manager.responseSerializer = [AFJSONResponseSerializer serializer]; break; } case kHYBResponseTypeXML: { manager.responseSerializer = [AFXMLParserResponseSerializer serializer]; break; } case kHYBResponseTypeData: { manager.responseSerializer = [AFHTTPResponseSerializer serializer]; break; } default: { break; } } manager.requestSerializer.stringEncoding = NSUTF8StringEncoding; for (NSString *key in sg_httpHeaders.allKeys) { if (sg_httpHeaders[key] != nil) { [manager.requestSerializer setValue:sg_httpHeaders[key] forHTTPHeaderField:key]; } } manager.responseSerializer.acceptableContentTypes = [NSSet setWithArray:@[@"application/json", @"text/html", @"text/json", @"text/plain", @"text/javascript", @"text/xml", @"image/*"]]; manager.requestSerializer.timeoutInterval = sg_timeout; // 设置允许同时最大并发数量,过大容易出问题 manager.operationQueue.maxConcurrentOperationCount = 3; sg_sharedManager = manager; } } return sg_sharedManager; } + (void)detectNetwork { AFNetworkReachabilityManager *reachabilityManager = [AFNetworkReachabilityManager sharedManager]; [reachabilityManager startMonitoring]; [reachabilityManager setReachabilityStatusChangeBlock:^(AFNetworkReachabilityStatus status) { if (status == AFNetworkReachabilityStatusNotReachable){ sg_networkStatus = kHYBNetworkStatusNotReachable; } else if (status == AFNetworkReachabilityStatusUnknown){ sg_networkStatus = kHYBNetworkStatusUnknown; } else if (status == AFNetworkReachabilityStatusReachableViaWWAN){ sg_networkStatus = kHYBNetworkStatusReachableViaWWAN; } else if (status == AFNetworkReachabilityStatusReachableViaWiFi){ sg_networkStatus = kHYBNetworkStatusReachableViaWiFi; } }]; } + (void)logWithSuccessResponse:(id)response url:(NSString *)url params:(NSDictionary *)params { HYBAppLog(@" "); HYBAppLog(@" Request success, URL: %@ params:%@ response:%@ ", [self generateGETAbsoluteURL:url params:params], params, [self tryToParseData:response]); } + (void)logWithFailError:(NSError *)error url:(NSString *)url params:(id)params { NSString *format = @" params: "; if (params == nil || ![params isKindOfClass:[NSDictionary class]]) { format = @""; params = @""; } HYBAppLog(@" "); if ([error code] == NSURLErrorCancelled) { HYBAppLog(@" Request was canceled mannully, URL: %@ %@%@ ", [self generateGETAbsoluteURL:url params:params], format, params); } else { HYBAppLog(@" Request error, URL: %@ %@%@ errorInfos:%@ ", [self generateGETAbsoluteURL:url params:params], format, params, [error localizedDescription]); } } // 仅对一级字典结构起作用 + (NSString *)generateGETAbsoluteURL:(NSString *)url params:(id)params { if (params == nil || ![params isKindOfClass:[NSDictionary class]] || [params count] == 0) { return url; } NSString *queries = @""; for (NSString *key in params) { id value = [params objectForKey:key]; if ([value isKindOfClass:[NSDictionary class]]) { continue; } else if ([value isKindOfClass:[NSArray class]]) { continue; } else if ([value isKindOfClass:[NSSet class]]) { continue; } else { queries = [NSString stringWithFormat:@"%@%@=%@&", (queries.length == 0 ? @"&" : queries), key, value]; } } if (queries.length > 1) { queries = [queries substringToIndex:queries.length - 1]; } if (([url hasPrefix:@"http://"] || [url hasPrefix:@"https://"]) && queries.length > 1) { if ([url rangeOfString:@"?"].location != NSNotFound || [url rangeOfString:@"#"].location != NSNotFound) { url = [NSString stringWithFormat:@"%@%@", url, queries]; } else { queries = [queries substringFromIndex:1]; url = [NSString stringWithFormat:@"%@?%@", url, queries]; } } return url.length == 0 ? queries : url; } + (NSString *)encodeUrl:(NSString *)url { return [self hyb_URLEncode:url]; } + (id)tryToParseData:(id)responseData { if ([responseData isKindOfClass:[NSData class]]) { // 尝试解析成JSON if (responseData == nil) { return responseData; } else { NSError *error = nil; NSDictionary *response = [NSJSONSerialization JSONObjectWithData:responseData options:NSJSONReadingMutableContainers error:&error]; if (error != nil) { return responseData; } else { return response; } } } else { return responseData; } } + (void)successResponse:(id)responseData callback:(HYBResponseSuccess)success { if (success) { success([self tryToParseData:responseData]); } } + (NSString *)hyb_URLEncode:(NSString *)url { return [url stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; // 采用下面的方式反而不能请求成功 // NSString *newString = // CFBridgingRelease(CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault, // (CFStringRef)url, // NULL, // CFSTR(":/?#[]@!$ &'()*+,;="<>%{}|\^~`"), CFStringConvertNSStringEncodingToEncoding(NSUTF8StringEncoding))); // if (newString) { // return newString; // } // // return url; } + (id)cahceResponseWithURL:(NSString *)url parameters:params { id cacheData = nil; if (url) { // Try to get datas from disk NSString *directoryPath = cachePath(); NSString *absoluteURL = [self generateGETAbsoluteURL:url params:params]; NSString *key = [NSString hybnetworking_md5:absoluteURL]; NSString *path = [directoryPath stringByAppendingPathComponent:key]; NSData *data = [[NSFileManager defaultManager] contentsAtPath:path]; if (data) { cacheData = data; HYBAppLog(@"Read data from cache for url: %@ ", url); } } return cacheData; } + (void)cacheResponseObject:(id)responseObject request:(NSURLRequest *)request parameters:params { if (request && responseObject && ![responseObject isKindOfClass:[NSNull class]]) { NSString *directoryPath = cachePath(); NSError *error = nil; if (![[NSFileManager defaultManager] fileExistsAtPath:directoryPath isDirectory:nil]) { [[NSFileManager defaultManager] createDirectoryAtPath:directoryPath withIntermediateDirectories:YES attributes:nil error:&error]; if (error) { HYBAppLog(@"create cache dir error: %@ ", error); return; } } NSString *absoluteURL = [self generateGETAbsoluteURL:request.URL.absoluteString params:params]; NSString *key = [NSString hybnetworking_md5:absoluteURL]; NSString *path = [directoryPath stringByAppendingPathComponent:key]; NSDictionary *dict = (NSDictionary *)responseObject; NSData *data = nil; if ([dict isKindOfClass:[NSData class]]) { data = responseObject; } else { data = [NSJSONSerialization dataWithJSONObject:dict options:NSJSONWritingPrettyPrinted error:&error]; } if (data && error == nil) { BOOL isOk = [[NSFileManager defaultManager] createFileAtPath:path contents:data attributes:nil]; if (isOk) { HYBAppLog(@"cache file ok for request: %@ ", absoluteURL); } else { HYBAppLog(@"cache file error for request: %@ ", absoluteURL); } } } } + (NSString *)absoluteUrlWithPath:(NSString *)path { if (path == nil || path.length == 0) { return @""; } if ([self baseUrl] == nil || [[self baseUrl] length] == 0) { return path; } NSString *absoluteUrl = path; if (![path hasPrefix:@"http://"] && ![path hasPrefix:@"https://"]) { if ([[self baseUrl] hasSuffix:@"/"]) { if ([path hasPrefix:@"/"]) { NSMutableString * mutablePath = [NSMutableString stringWithString:path]; [mutablePath deleteCharactersInRange:NSMakeRange(0, 1)]; absoluteUrl = [NSString stringWithFormat:@"%@%@", [self baseUrl], mutablePath]; } else { absoluteUrl = [NSString stringWithFormat:@"%@%@",[self baseUrl], path]; } } else { if ([path hasPrefix:@"/"]) { absoluteUrl = [NSString stringWithFormat:@"%@%@",[self baseUrl], path]; } else { absoluteUrl = [NSString stringWithFormat:@"%@/%@", [self baseUrl], path]; } } } return absoluteUrl; } + (void)handleCallbackWithError:(NSError *)error fail:(HYBResponseFail)fail { if ([error code] == NSURLErrorCancelled) { if (sg_shouldCallbackOnCancelRequest) { if (fail) { fail(error); } } } else { if (fail) { fail(error); } } } @end
    #import <Foundation/Foundation.h>
    #import <UIKit/UIKit.h>
    
    // 项目打包上线都不会打印日志,因此可放心。
    #ifdef DEBUG
    #define HYBAppLog(s, ... ) NSLog( @"[%@ in line %d] ===============>%@", [[NSString stringWithUTF8String:__FILE__] lastPathComponent], __LINE__, [NSString stringWithFormat:(s), ##__VA_ARGS__] )
    #else
    #define HYBAppLog(s, ... )
    #endif
    
    /*!
     *  @author 黄, 16-01-08 14:01:26
     *
     *  下载进度
     *
     *  @param bytesRead                 已下载的大小
     *  @param totalBytesRead            文件总大小
     *  @param totalBytesExpectedToRead 还有多少需要下载
     */
    typedef void (^HYBDownloadProgress)(int64_t bytesRead,
                                        int64_t totalBytesRead);
    
    typedef HYBDownloadProgress HYBGetProgress;
    typedef HYBDownloadProgress HYBPostProgress;
    
    /*!
     *  @author 黄, 16-01-08 14:01:26
     *
     *  上传进度
     *
     *  @param bytesWritten              已上传的大小
     *  @param totalBytesWritten         总上传大小
     */
    typedef void (^HYBUploadProgress)(int64_t bytesWritten,
                                      int64_t totalBytesWritten);
    
    typedef NS_ENUM(NSUInteger, HYBResponseType) {
      kHYBResponseTypeJSON = 1, // 默认
      kHYBResponseTypeXML  = 2, // XML
      // 特殊情况下,一转换服务器就无法识别的,默认会尝试转换成JSON,若失败则需要自己去转换
      kHYBResponseTypeData = 3
    };
    
    typedef NS_ENUM(NSUInteger, HYBRequestType) {
      kHYBRequestTypeJSON = 1, // 默认
      kHYBRequestTypePlainText  = 2 // 普通text/html
    };
    
    typedef NS_ENUM(NSInteger, HYBNetworkStatus) {
        kHYBNetworkStatusUnknown          = -1,//未知网络
        kHYBNetworkStatusNotReachable     = 0,//网络无连接
        kHYBNetworkStatusReachableViaWWAN = 1,//2,3,4G网络
        kHYBNetworkStatusReachableViaWiFi = 2,//WIFI网络
    };
    
    @class NSURLSessionTask;
    
    // 请勿直接使用NSURLSessionDataTask,以减少对第三方的依赖
    // 所有接口返回的类型都是基类NSURLSessionTask,若要接收返回值
    // 且处理,请转换成对应的子类类型
    typedef NSURLSessionTask HYBURLSessionTask;
    typedef void(^HYBResponseSuccess)(id response);
    typedef void(^HYBResponseFail)(NSError *error);
    
    /*!
     *  @author huangyibiao, 15-11-15 13:11:31
     *
     *  基于AFNetworking的网络层封装类.
     *
     *  @note 这里只提供公共api
     */
    @interface HYBNetworking : NSObject
    
    /*!
     *  @author 黄, 15-11-15 13:11:45
     *
     *  用于指定网络请求接口的基础url,如:
     *  http://henishuo.com或者http://101.200.209.244
     *  通常在AppDelegate中启动时就设置一次就可以了。如果接口有来源
     *  于多个服务器,可以调用更新
     *
     *  @param baseUrl 网络接口的基础url
     */
    + (void)updateBaseUrl:(NSString *)baseUrl;
    + (NSString *)baseUrl;
    
    /**
     *    设置请求超时时间,默认为60秒
     *
     *    @param timeout 超时时间
     */
    + (void)setTimeout:(NSTimeInterval)timeout;
    
    /**
     *    当检查到网络异常时,是否从从本地提取数据。默认为NO。一旦设置为YES,当设置刷新缓存时,
     *  若网络异常也会从缓存中读取数据。同样,如果设置超时不回调,同样也会在网络异常时回调,除非
     *  本地没有数据!
     *
     *    @param shouldObtain    YES/NO
     */
    + (void)obtainDataFromLocalWhenNetworkUnconnected:(BOOL)shouldObtain;
    
    /**
     *    @author 黄
     *
     *    默认只缓存GET请求的数据,对于POST请求是不缓存的。如果要缓存POST获取的数据,需要手动调用设置
     *  对JSON类型数据有效,对于PLIST、XML不确定!
     *
     *    @param isCacheGet            默认为YES
     *    @param shouldCachePost    默认为NO
     */
    + (void)cacheGetRequest:(BOOL)isCacheGet shoulCachePost:(BOOL)shouldCachePost;
    
    /**
     *    @author 黄
     *
     *    获取缓存总大小/bytes
     *
     *    @return 缓存大小
     */
    + (unsigned long long)totalCacheSize;
    
    /**
     *    默认不会自动清除缓存,如果需要,可以设置自动清除缓存,并且需要指定上限。当指定上限>0M时,
     *  若缓存达到了上限值,则每次启动应用则尝试自动去清理缓存。
     *
     *    @param mSize                缓存上限大小,单位为M(兆),默认为0,表示不清理
     */
    + (void)autoToClearCacheWithLimitedToSize:(NSUInteger)mSize;
    
    /**
     *    @author 黄
     *
     *    清除缓存
     */
    + (void)clearCaches;
    
    /*!
     *  @author 黄, 15-11-15 14:11:40
     *
     *  开启或关闭接口打印信息
     *
     *  @param isDebug 开发期,最好打开,默认是NO
     */
    + (void)enableInterfaceDebug:(BOOL)isDebug;
    
    /*!
     *  @author 黄, 15-12-25 15:12:45
     *
     *  配置请求格式,默认为JSON。如果要求传XML或者PLIST,请在全局配置一下
     *
     *  @param requestType 请求格式,默认为JSON
     *  @param responseType 响应格式,默认为JSO,
     *  @param shouldAutoEncode YES or NO,默认为NO,是否自动encode url
     *  @param shouldCallbackOnCancelRequest 当取消请求时,是否要回调,默认为YES
     */
    + (void)configRequestType:(HYBRequestType)requestType
                 responseType:(HYBResponseType)responseType
          shouldAutoEncodeUrl:(BOOL)shouldAutoEncode
      callbackOnCancelRequest:(BOOL)shouldCallbackOnCancelRequest;
    
    /*!
     *  @author 黄, 15-11-16 13:11:41
     *
     *  配置公共的请求头,只调用一次即可,通常放在应用启动的时候配置就可以了
     *
     *  @param httpHeaders 只需要将与服务器商定的固定参数设置即可
     */
    + (void)configCommonHttpHeaders:(NSDictionary *)httpHeaders;
    
    /**
     *    @author 黄
     *
     *    取消所有请求
     */
    + (void)cancelAllRequest;
    /**
     *    @author 黄
     *
     *    取消某个请求。如果是要取消某个请求,最好是引用接口所返回来的HYBURLSessionTask对象,
     *  然后调用对象的cancel方法。如果不想引用对象,这里额外提供了一种方法来实现取消某个请求
     *
     *    @param url                URL,可以是绝对URL,也可以是path(也就是不包括baseurl)
     */
    + (void)cancelRequestWithURL:(NSString *)url;
    
    /*!
     *  @author 黄, 15-11-15 13:11:50
     *
     *  GET请求接口,若不指定baseurl,可传完整的url
     *
     *  @param url     接口路径,如/path/getArticleList
     *  @param refreshCache 是否刷新缓存。由于请求成功也可能没有数据,对于业务失败,只能通过人为手动判断
     *  @param params  接口中所需要的拼接参数,如@{"categoryid" : @(12)}
     *  @param success 接口成功请求到数据的回调
     *  @param fail    接口请求数据失败的回调
     *
     *  @return 返回的对象中有可取消请求的API
     */
    + (HYBURLSessionTask *)getWithUrl:(NSString *)url
                         refreshCache:(BOOL)refreshCache
                              success:(HYBResponseSuccess)success
                                 fail:(HYBResponseFail)fail;
    // 多一个params参数
    + (HYBURLSessionTask *)getWithUrl:(NSString *)url
                         refreshCache:(BOOL)refreshCache
                               params:(NSDictionary *)params
                              success:(HYBResponseSuccess)success
                                 fail:(HYBResponseFail)fail;
    // 多一个带进度回调
    + (HYBURLSessionTask *)getWithUrl:(NSString *)url
                         refreshCache:(BOOL)refreshCache
                               params:(NSDictionary *)params
                             progress:(HYBGetProgress)progress
                              success:(HYBResponseSuccess)success
                                 fail:(HYBResponseFail)fail;
    
    /*!
     *  @author 黄, 15-11-15 13:11:50
     *
     *  POST请求接口,若不指定baseurl,可传完整的url
     *
     *  @param url     接口路径,如/path/getArticleList
     *  @param params  接口中所需的参数,如@{"categoryid" : @(12)}
     *  @param success 接口成功请求到数据的回调
     *  @param fail    接口请求数据失败的回调
     *
     *  @return 返回的对象中有可取消请求的API
     */
    + (HYBURLSessionTask *)postWithUrl:(NSString *)url
                          refreshCache:(BOOL)refreshCache
                                params:(NSDictionary *)params
                               success:(HYBResponseSuccess)success
                                  fail:(HYBResponseFail)fail;
    + (HYBURLSessionTask *)postWithUrl:(NSString *)url
                          refreshCache:(BOOL)refreshCache
                                params:(NSDictionary *)params
                              progress:(HYBPostProgress)progress
                               success:(HYBResponseSuccess)success
                                  fail:(HYBResponseFail)fail;
    /**
     *    @author 黄, 16-01-31 00:01:40
     *
     *    图片上传接口,若不指定baseurl,可传完整的url
     *
     *    @param image            图片对象
     *    @param url                上传图片的接口路径,如/path/images/
     *    @param filename        给图片起一个名字,默认为当前日期时间,格式为"yyyyMMddHHmmss",后缀为`jpg`
     *    @param name                与指定的图片相关联的名称,这是由后端写接口的人指定的,如imagefiles
     *    @param mimeType        默认为image/jpeg
     *    @param parameters    参数
     *    @param progress        上传进度
     *    @param success        上传成功回调
     *    @param fail                上传失败回调
     *
     *    @return
     */
    + (HYBURLSessionTask *)uploadWithImage:(UIImage *)image
                                       url:(NSString *)url
                                  filename:(NSString *)filename
                                      name:(NSString *)name
                                  mimeType:(NSString *)mimeType
                                parameters:(NSDictionary *)parameters
                                  progress:(HYBUploadProgress)progress
                                   success:(HYBResponseSuccess)success
                                      fail:(HYBResponseFail)fail;
    
    /**
     *    @author 黄, 16-01-31 00:01:59
     *
     *    上传文件操作
     *
     *    @param url                        上传路径
     *    @param uploadingFile    待上传文件的路径
     *    @param progress            上传进度
     *    @param success                上传成功回调
     *    @param fail                    上传失败回调
     *
     *    @return
     */
    + (HYBURLSessionTask *)uploadFileWithUrl:(NSString *)url
                               uploadingFile:(NSString *)uploadingFile
                                    progress:(HYBUploadProgress)progress
                                     success:(HYBResponseSuccess)success
                                        fail:(HYBResponseFail)fail;
    
    
    /*!
     *  @author 黄, 16-01-08 15:01:11
     *
     *  下载文件
     *
     *  @param url           下载URL
     *  @param saveToPath    下载到哪个路径下
     *  @param progressBlock 下载进度
     *  @param success       下载成功后的回调
     *  @param failure       下载失败后的回调
     */
    + (HYBURLSessionTask *)downloadWithUrl:(NSString *)url
                                saveToPath:(NSString *)saveToPath
                                  progress:(HYBDownloadProgress)progressBlock
                                   success:(HYBResponseSuccess)success
                                   failure:(HYBResponseFail)failure;
    
    @end

    使用:

      // 通常放在appdelegate就可以了
      [HYBNetworking updateBaseUrl:@"http://apistore.baidu.com"];
      [HYBNetworking enableInterfaceDebug:YES];
      
      // 配置请求和响应类型,由于部分伙伴们的服务器不接收JSON传过去,现在默认值改成了plainText
      [HYBNetworking configRequestType:kHYBRequestTypePlainText
                          responseType:kHYBResponseTypeJSON
                   shouldAutoEncodeUrl:YES
               callbackOnCancelRequest:NO];
      
      /*
       [HYBNetworking.m:in line: 189]-->[message:
       absoluteUrl: http://apistore.baidu.com/microservice/cityinfo?cityname=%E5%8C%97%E4%BA%AC
       params:(null)
       response:{
       errNum = 0;
       retData =     {
       cityCode = 101010100;
       cityName = "U5317U4eac";
       provinceName = "U5317U4eac";
       telAreaCode = 010;
       zipCode = 100000;
       };
       retMsg = success;
       }
       ]
       */
      
      // 设置GET、POST请求都缓存
      [HYBNetworking cacheGetRequest:YES shoulCachePost:YES];
      
      // 测试GET API
      NSString *url = @"http://api.map.baidu.com/telematics/v3/weather?location=嘉兴&output=json&ak=5slgyqGDENN7Sy7pw29IUvrZ";
      //   设置请求类型为text/html类型
      //  [HYBNetworking configRequestType:kHYBRequestTypePlainText];
      //  [HYBNetworking configResponseType:kHYBResponseTypeData];
      // 如果请求回来的数据是业务数据,但是是失败的,这时候需要外部开发人员才能判断是业务失败。
      // 内部处理是只有走failure的才能判断为无效数据,才不会缓存
      // 如果设置为YES,则每次会去刷新缓存,也就是不会读取缓存,即使已经缓存起来
      // 新下载的数据会重新缓存起来
      [HYBNetworking getWithUrl:url refreshCache:NO params:nil progress:^(int64_t bytesRead, int64_t totalBytesRead) {
        NSLog(@"progress: %f, cur: %lld, total: %lld",
              (bytesRead * 1.0) / totalBytesRead,
              bytesRead,
              totalBytesRead);
      } success:^(id response) {
        
      } fail:^(NSError *error) {
        
      }];
      
      
      // 测试POST API:
      // 假数据
      NSDictionary *postDict = @{ @"urls": @"http://www.henishuo.com/git-use-inwork/",
                                  @"goal" : @"site",
                                  @"total" : @(123)
                                  };
      NSString *path = @"/urls?site=www.henishuo.com&token=bRidefmXoNxIi3Jp";
      // 由于这里有两套基础路径,用时就需要更新
      [HYBNetworking updateBaseUrl:@"http://data.zz.baidu.com"];
      // 每次刷新缓存
      // 如果获取到的业务数据是不正确的,则需要下次调用时设置为YES,表示要刷新缓存
    // HYBURLSessionTask *task =
      [HYBNetworking postWithUrl:path refreshCache:YES params:postDict success:^(id response) {
        
      } fail:^(NSError *error) {
        
      }];
      
      // 取消全部请求
    //  [HYBNetworking cancelAllRequest];
      
      // 取消单个请求方法一
    //  [HYBNetworking cancelRequestWithURL:path];
      
      // 取消单个请求方法二
    //  [task cancel];
      
      NSLog(@"%lld", [HYBNetworking totalCacheSize]);
    //  [HYBNetworking clearCaches];
      
       path = [NSHomeDirectory() stringByAppendingPathComponent:@"Documents/b.zip"];
    [HYBNetworking downloadWithUrl:@"http://wiki.lbsyun.baidu.com/cms/iossdk/sdk/BaiduMap_IOSSDK_v2.10.2_All.zip" saveToPath:path progress:^(int64_t bytesRead, int64_t totalBytesRead) {
        
      } success:^(id response) {
        
      } failure:^(NSError *error) {
        
      }];
    //  NSLog(@"%@", task);
    }
  • 相关阅读:
    柔性数组
    2015阿里秋招当中一个算法题(经典)
    LAMP环境搭建
    JS和JQuery中的事件托付 学习笔记
    #17 Letter Combinations of a Phone Number
    码农生涯杂记_5
    【C++ Primer每日刷】之三 标准库 string 类型
    扎根本地连接未来 千米网的电商“红海”生存术
    poj 3356
    经验之谈—OAuth授权流程图
  • 原文地址:https://www.cnblogs.com/HJQ2016/p/5968327.html
Copyright © 2020-2023  润新知