iOS 工作中封裝通用性網(wǎng)絡請求框架

在iOS開發(fā)中,網(wǎng)絡是必不可少的一部分,沒有人不知道大名鼎鼎的AFNetwork框架的前翎,因為它提供了非常豐富實用,方便的網(wǎng)絡調用畅涂。使得很多需求都能夠調用已有的方法完成鱼填。但是面對業(yè)務需求,如何合理的將AFNetwork近一步封裝能夠更加方便的完成業(yè)務需求卻是需要好好考慮的毅戈。以下根據(jù)自己的工作經(jīng)歷中對AFNetwork的封裝苹丸。

一、首次接觸


自己在A公司的時候剛剛接觸iOS不久苇经,看到的工程中已經(jīng)存在的封裝是這樣子的

+ (void)postJSONWithUrl:(NSString *)urlStr parameters:(NSMutableDictionary *)dic success:(void (^)(id responseObject))success fail:(void (^)())fail;
+ (void)JSONDataWithUrl:(NSString *)url andDic:(NSMutableDictionary *)dic success:(void (^)(id json))success fail:(void (^)(id error))fail;

這兩個函數(shù)很簡單赘理,就是發(fā)起一個網(wǎng)絡請求,使用的時候urlStr基本上就是固定的用宏來定義的扇单。dic就是傳遞的字典.success 和fail 分別表示請求成功和失敗的回調商模。但是他們缺點重重,最明顯的

  • post和get應該可以用一個方法來實現(xiàn)的蜘澜。
  • urlStr每次都寫都要寫太麻煩施流。

二、接觸正規(guī)需求


后來就是現(xiàn)在的公司了鄙信,因為業(yè)務需求比較正規(guī)了瞪醋,iOS客戶端又是剛剛開始研發(fā),所以跟我提了一系列需求装诡,讓我封裝一套通用網(wǎng)絡方法银受,相信這也是大部分互聯(lián)網(wǎng)公司的需求吧,只是我以前見識太少鸦采。

  • 網(wǎng)絡請求的數(shù)據(jù)要能夠緩存,但是也可以不進行緩存,緩存的數(shù)據(jù)還要可以設置緩存時間。
  • 對于每次網(wǎng)絡請求要優(yōu)先從緩存中讀取內容,如果緩存讀取成功,就用回調成功block,然后檢查緩存是否過期互墓,過期就從網(wǎng)絡請求數(shù)據(jù)判莉,然后把新的數(shù)據(jù)存入到緩存中锰镀。
  • 網(wǎng)絡請求的結果:
    • 成功獲得數(shù)據(jù)
    • 請求數(shù)據(jù)失敗、返回特殊狀態(tài)碼。(用戶沒有登陸,已經(jīng)是最新數(shù)據(jù)等等)

緩存的應用場景主要是tableview加載數(shù)據(jù)膏潮,其他的場景也適合,以下以tableview為例

  • 首次進入一個界面tableview的數(shù)據(jù)應該先讀取緩存,主要防止沒有網(wǎng)絡或者網(wǎng)絡不好的情況下用戶等待數(shù)據(jù)時間過長或者沒有數(shù)據(jù)用戶體驗不好,主要用于某些tableview請求的數(shù)據(jù)量很大顷歌,或者數(shù)據(jù)短時間內變化不是很快的地方。
  • 用戶下拉刷新表示重新請求數(shù)據(jù)舱卡,應該強制更新數(shù)據(jù)浮禾,不論本地是否有緩存,但是這部分數(shù)據(jù)應該存入數(shù)據(jù)庫,保證退出后下次進入界面的時候能夠讀取最后更新的緩存。
  • 上拉加載更多的時候不讀緩存歪今,因為如果客戶端自己在處理這部分邏輯比較復雜嫉晶,不是說實現(xiàn)起來復雜泊柬,因為對于本地存儲來說調用的是統(tǒng)一的一個方法剪况,主要是因為如果用戶下拉刷新需要強制更新數(shù)據(jù)蒲跨,不論本地有無緩存译断,都要從服務器請求最新數(shù)據(jù)。那么問題來了或悲,如果我把用戶上拉加載更多時候的數(shù)據(jù)也存入本地孙咪,假設用戶上拉加載了5頁數(shù)據(jù)堪唐,然后又強制下拉刷新了一下,這個時候tableview顯示的是最新的第一頁數(shù)據(jù)翎蹈,如果接著上拉加載更多我應該是讀取緩存還是直接發(fā)起網(wǎng)絡請求呢淮菠。毫無疑問應該直接發(fā)起請求,因為下拉強制刷新已經(jīng)導致了第一頁為最新數(shù)據(jù)荤堪,如果第2-5頁數(shù)據(jù)緩存沒有過期并且服務器數(shù)據(jù)確實變化了的話合陵,客戶端將得不到新的數(shù)據(jù),所以僅僅第一次進入tableview界面澄阳,請求第一頁數(shù)據(jù)的時候要讀緩存拥知。
  • 根本不用緩存的地方主要是某些數(shù)據(jù)變化非常快碎赢,或者發(fā)起的網(wǎng)絡請求是一次性的操作低剔,比如收藏某個題目等等。

根據(jù)上面的需求肮塞,我首先想到用sqlite作為緩存的數(shù)據(jù)庫襟齿,面對一個完整的url和url請求得到的json字符串提供增刪改查,用了一天時間我封裝了屬于工程的數(shù)據(jù)庫枕赵。提供了如下接口

/**
 *  插入一個json緩存數(shù)據(jù)
 *  @param key         鍵
 *  @param value       數(shù)據(jù)
 *  @param expire_time 過期時間
 */
+ (void)insertJonsCacheStringWithKey:(NSString *)key andWithValue:(NSString*) value andWithExpireTime:(NSInteger )expire_time;

/**
 *  根據(jù)JSON緩存獲取一個包含對JSON數(shù)據(jù)操作的對象
 *  @param key 鍵
 *  @return --- JsonCacheData類型的可以對提取的json處理
 */
+(JsonCacheData *)queryJsonCacheTableWithKey:(NSString *)key;

/**
 *  插入的值是字典類型
 *  @param key         鍵
 *  @param value       值
 *  @param expire_time 過期時間
 */
+ (void)insertJsonCacheDictWithKey:(NSString *)key andWithValue:(NSDictionary*) value andWithExpireTime:(NSInteger )expire_time;
/**
 *  刪除數(shù)據(jù)緩存
 *  @param key
 */
+ (BOOL)deleteJsonCacheDictWithKey:(NSString *)key;

并且創(chuàng)建了一個JsonCacheData對象存儲數(shù)據(jù)庫的數(shù)據(jù)猜欺,因為有的時候存入數(shù)據(jù)庫的不一定是json,很可能是個字符串什么烁设,這樣可以按照不同的需求調用類里面的方法得到自己想要的數(shù)據(jù)類型.

@interface JsonCacheData : NSObject
//數(shù)據(jù)存入數(shù)據(jù)庫的時間戳
@property (nonatomic,assign) NSInteger saveTime;
//緩存有效期長度
@property (nonatomic,assign) NSInteger expireTime;
//從數(shù)據(jù)庫返回的字符串信息
@property (nonatomic,strong) NSString * jsonCache;
-(BOOL)isExpire;
/**
 *  轉換成JSON類型
 *  @return JSON數(shù)據(jù)的字典
 */
-(NSDictionary *)JsonData;
@end

AFNet封裝完成后函數(shù)如下

/**
 *  網(wǎng)絡請求數(shù)據(jù)的方法替梨,可以進行緩存
 *  @param param     上傳請求的參數(shù)
 *  @param success   獲取的json數(shù)據(jù),可能是網(wǎng)絡請求的装黑,也可能是本地緩存的
 *  @param codeError 網(wǎng)絡返回數(shù)據(jù)的錯誤碼
 *  @param fail      網(wǎng)絡連接失敗
 *  @param minutes   緩存的有效時長
 */
+(void)loadDataWithCache:(NSDictionary *) param NetBlock:(void (^)(NSDictionary *json))success ErrorCode :(void(^)(int errorCode))codeError Fail:(void(^)())fail cacheTime:(int) minutes
{
    NSMutableDictionary * dict = [NSMutableDictionary dictionaryWithDictionary:param];
    NSString * sqliteKey = [HSNetUrlProcess createSqliteKeyWithParm:dict];
    JsonCacheData * data = [SQLiteJsonCache queryJsonCacheTableWithKey:sqliteKey];
    //緩存存在并且副瀑,緩存時間大于0表示要求讀取緩存的
    if (data.jsonCache.length>0&&minutes>0)
    {
        if (data.jsonCache.length>0) { //如果緩存存在, 有緩存就顯示,并且緩存時間要大于0否則就沒有意義
            if (success!=nil) {
                success(data.JsonData);
            }
            if (data.isExpire) {
                if ([data.JsonData[@"version"]length]>0) {
                    dict[@"version"]=data.JsonData[@"version"];
                }
                //這里調用網(wǎng)絡方法請求數(shù)據(jù)
                [AFNetworkTool JSONDataWithDic:dict success:^(id json) {
                    if (json!=nil) {
                        //加密
                        [SQLiteJsonCache insertJsonCacheDictWithKey:sqliteKey andWithValue:json andWithExpireTime:60*minutes];
                        success(json);
                    }
                } codeError:^(int errorCode) {
                    if (codeError!=nil) {
                        if (errorCode==NetCode_RESULT_NEWEST) { //更新緩存的時間恋谭,已經(jīng)是最新數(shù)據(jù)
                            [SQLiteJsonCache insertJsonCacheDictWithKey:sqliteKey andWithValue:data.JsonData andWithExpireTime:minutes*60];
                        }
                        codeError(errorCode);
                    }
                } fail:^{
                    
                    if (fail!=nil) {
                        fail();
                    }
                }];
            }
        }
    }
    else //這里是不讀取緩存
    {
        [AFNetworkTool JSONDataWithDic:dict success:^(id json) {
            if (minutes!=CACHE_NO_SAVE) { // CACHE_NO_SAVE = -1 表示不需要存入數(shù)據(jù)庫糠睡。
                [SQLiteJsonCache insertJsonCacheDictWithKey:sqliteKey andWithValue:json andWithExpireTime:minutes*60];
            }
            success(json);
        } codeError:^(int errorCode) {
            if (codeError!=nil) {
                codeError(errorCode);
            }
        } fail:^{
            if (fail!=nil) {
                fail();
            }
        }];
    }
}

傳遞的cachetime有以下類型

CACHE_NOSAVE CACHE_NOREAD CACHE_READ_NORMAL
-1 0 10
不讀緩存 不讀取緩存,但是要將獲取的數(shù)據(jù)按照CACHE_READ_NO有效期存儲 大部分情況下緩存有效期

上面的封裝也不太好疚颊,但是時間太緊迫狈孔,趕鴨子上架,而且都等著用我寫的網(wǎng)絡方法呢材义,所有就先這樣了均抽,在使用的時候暴露了很多問題:

  • 網(wǎng)絡請求有的時候需要控制SVProgressHud的顯示,但是很多場合用其掂,要么多了油挥,要么少了,每次網(wǎng)絡調用需要自己加麻煩。
  • 真正使用起來雞肋深寥,為了完成上述tableview請求數(shù)據(jù)的需求攘乒。我們只能這樣做
    self.cacheTime = CACHE_NO_NORMAL;
    [AFNetworkTool loadDataWithCache:dict NetBlock:^(NSDictionary *json) {
        self.cacheTime = CACHE_NO_READ;
        //process data
    } ErrorCode:^(int errorCode) {
    } Fail:^{
    } cacheTime:self.cacheTime];

用一個全局變量保存緩存策略然后請求數(shù)據(jù)后在改,一個界面如果存在兩個同的網(wǎng)絡請求都用到緩存惋鹅,就要定義兩個cachetime.太麻煩了则酝,不能忍。


解決方案

  1. 我想我可以通過給網(wǎng)絡調用添加參數(shù)的形式方式擴展功能闰集,但是放棄了沽讹,因為如果給原來的方法添加一個參數(shù),工程所有的調用的地方都要改返十,實在麻煩妥泉,如果原來的方法保留,復制一下加個參數(shù)工程中會多出很多冗余代碼洞坑,而且參數(shù)過多調用起來也不方便。
  2. 自定義一個網(wǎng)絡配置類 NetSetting蝇率,包含發(fā)起一次網(wǎng)絡請求所有的控制策略迟杂,將類的對象作為網(wǎng)絡調用的參數(shù),網(wǎng)絡如何發(fā)起完全根據(jù)傳遞的NetSetting對象的設置
    所以最終經(jīng)過我的不斷修改一個能夠適用于所有需求的網(wǎng)絡請求成功了本慕。

NetSetting類包含了所有的設置排拷,包括請求方式緩存策略锅尘,是否加密监氢,是否自己單獨控制SVProgressHud的顯示

typedef NS_ENUM(int, HSCacheTime) {
    
    HSCacheNoRead = 0,
    HSCacheNoSave = -1,
    HSCacheNormal = 5,
    HSCacheOneMinute = 1,
    HSCacheOneDay = 24*60,
};
typedef enum
{
    NetMethodPOST = 0,
    NetMethodGET = 1,
}NetMethod;
@interface HSNetSetting : NSObject
//加載動畫控制方式藤违,yes表示由調用的控制器控制浪腐,NO表示有AFNetWork類控制
@property (nonatomic,assign) BOOL isCtrlHub;
//緩存的策略
@property (nonatomic,assign) HSCacheTime cachePolicy;
//是否加密
@property (nonatomic,assign) BOOL isEncrypt;
//獲取數(shù)據(jù)的方式,get請求或者post請求
@property (nonatomic,assign) NetMethod askMethod;
//只讀緩存的內容
@property (nonatomic,assign) BOOL justReadCache;//啟動頁廣告會用到
//默認的設置
+(instancetype)noSaveCacheSet;//不寫緩存
+(instancetype)noReadCacheSet;//不讀緩存
+(instancetype)readCacheSet;//讀緩存
+(instancetype)noEncryptPost;

此時AFNetwork封裝的方法包含了兩個部分

  • 對外開放的部分顿乒,所有的網(wǎng)絡請求只能調用這個方法發(fā)起议街。改方法會根據(jù)netSetting的配置去合理的處理網(wǎng)絡請求的細節(jié)。
//這是對外提供的方法
+(void)HVDataCache:(NSDictionary *) param NetBlock:(void (^)(NSDictionary *json))success
                                        ErrorCode :(void(^)(int errorCode))codeError
                                              Fail:(void(^)())fail
                                           Setting:(HSNetSetting*)netSettting
{
    HSNetSetting * set = netSettting ;
    if (set == nil ) {
        set = [HSNetSetting noSaveCacheSet];//默認
        set.isEncrypt = YES;
    }
    NSMutableDictionary * dict = [NSMutableDictionary dictionaryWithDictionary:param];
    NSString * sqliteKey = [HSNetUrlProcess createSqliteKeyWithParm:dict];
    JsonCacheData * data = [SQLiteJsonCache queryJsonCacheTableWithKey:sqliteKey];
    //讀緩存璧榄,后面的null是服務器最近返回的錯誤數(shù)據(jù)特漩,
    if (data.jsonCache.length>0&&(set.cachePolicy>HSCacheNoRead||set.justReadCache==YES))
    {
        if (data.jsonCache.length>0) { //如果緩存存在, 有緩存就顯示,并且緩存時間要大于0否則就沒有意義
            if (success!=nil) {
                if (data.isExpire==NO) {
                     set.cachePolicy = HSCacheNoRead;
                }
                success(data.JsonData);
            }
            if (data.isExpire) { //要把version帶上骨杂,服務器用于md5計算涂身,是否返回數(shù)據(jù)
                if ([data.JsonData[@"version"]length]>0) {
                    dict[@"version"]=data.JsonData[@"version"];
                }
                int cache_span = [data.JsonData[@"cache_span"]intValue];
                cache_span = cache_span>24*60?60:cache_span;
                set.cachePolicy = cache_span;
                [AFNetworkTool HVJSONDataWithDic:dict success:^(id json) {
                    //加密
                    [SQLiteJsonCache insertJsonCacheDictWithKey:sqliteKey andWithValue:json andWithExpireTime:set.cachePolicy*60];
                     set.cachePolicy = HSCacheNoRead;
                    if (set.justReadCache==NO) {
                        success(json);
                    }
                } codeError:^(int errorCode) {
                    if (codeError!=nil) {
                        if (errorCode==NetCode_RESULT_NEWEST) { //更新緩存的時間
                            [SQLiteJsonCache insertJsonCacheDictWithKey:sqliteKey andWithValue:data.JsonData andWithExpireTime:cache_span *60];
                        }
                        codeError(errorCode);
                    }
                } fail:^{
                    if (fail!=nil) {
                        fail();
                    }
                } Setting:set];
            }
        }
    }
    else
    {
        if (!set.isCtrlHub) {
            [SVProgressHUD show];
        }
        [AFNetworkTool HVJSONDataWithDic:dict success:^(id json) {
            if (!set.isCtrlHub) {
                [SVProgressHUD dismiss];
            }
            set.cachePolicy =  [json[@"cache_span"]intValue];
            if (set.cachePolicy!=HSCacheNoSave) {//判斷是不是  不存緩存
                 set.cachePolicy = HSCacheNoRead;
                [SQLiteJsonCache insertJsonCacheDictWithKey:sqliteKey andWithValue:json andWithExpireTime:set.cachePolicy*60];
            }
            if(set.justReadCache==NO)
            {
                success(json);
            }
            else
            {
                codeError(NetCode_NO_OLDDATA);//
            }
            
        } codeError:^(int errorCode) {
            if (codeError!=nil) {
                codeError(errorCode);
            }
            if (!set.isCtrlHub) {
                [SVProgressHUD dismiss];
            }
        } fail:^{
            
            [SVProgressHUD dismiss];
            if (fail!=nil) {
            fail();
        }
        } Setting:set];
    }
}

非對外開放的部分,該方法用于對外開放的方法的使用。

+ (void)HVJSONDataWithDic:(NSDictionary *)paramDict success:(void (^)(id json))success codeError:(void(^)(int errorCode))codeError  fail:(void (^)())fail Setting:(HSNetSetting*)netSettting
{
    AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
    manager.requestSerializer.timeoutInterval = 10.f;//設置請求超時的時間
    manager.responseSerializer.acceptableContentTypes = [NSSet setWithObjects:@"text/html",@"image/png",@"image/jpg", nil];
    //[manager.requestSerializer setValue:@"headers" forHTTPHeaderField:@"Referer: http://www.vyanke.com\n"];
    manager.responseSerializer = [AFHTTPResponseSerializer serializer];
    NSMutableDictionary * dict = [NSMutableDictionary dictionaryWithDictionary:paramDict];
    NSString * url;
    NSDictionary * param;
    //拼接將要訪問的URL地址
    NSDictionary * dict2 = [HSNetUrlProcess createCompDictWithParm:dict];
    NSString * value = [dict2 mj_JSONString];
    url = [HSNetUrlProcess createHeadURL:dict];
    NSLog(@"URL是%@",url);
    if (netSettting.isEncrypt==YES) {
        param = @{@"param":[EncryProcess textEncrypt:value]};
        NSLog(@"加密后完整參數(shù)%@",[EncryProcess textEncrypt:value]);
    }
    else
    {
        param = dict2;
    }
    if (netSettting.askMethod == NetMethodPOST) {
        
            [manager POST:url parameters:param progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
            //解密處理
            NSString * str = [[NSString alloc]initWithData:responseObject encoding:NSUTF8StringEncoding];
            if (netSettting.isEncrypt) {
                str = [EncryProcess textDecrypt:str];
                NSLog(@"解密后的參數(shù)=%@",str);
            }
            NSData *jsonData = [str dataUsingEncoding:NSUTF8StringEncoding];
            NSError *err;
            NSDictionary *JSON = [NSJSONSerialization JSONObjectWithData:jsonData
                                                                 options:NSJSONReadingMutableContainers
                                                                   error:&err];
            int code = [JSON[@"state"]intValue];
            if (success&&code==NetCode_NETWORK_SUCCESS) {
                success(JSON);
                return;
            }
            switch (code) {
                case NetCode_TOKEN_EXPIRE_ERROR://{
                {
                    [FLLoginDataModel currentUser].isLogin = NO;
                    [HSCoverView showMessage:JSON[@"msg"] finishBlock:nil];
                    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
                        [SVProgressHUD dismiss];//消失
                        HSLoginController * log = [[HSLoginController alloc]init];
                        log.hidesBottomBarWhenPushed =YES;
                        log.finishLoginBlock = ^{
                                    [AFNetworkTool HVJSONDataWithDic:paramDict success:success codeError:codeError fail:fail Setting:netSettting];
                            
                        };
                        if (![[HSTool getCurrentVC] isKindOfClass:[HSLoginController class]]) {
                            
                            [[HSTool getCurrentVC].navigationController pushViewController:log animated:YES];
                        }
    
                    });
                }
                default:
                    [HSCoverView showMessage:JSON[@"msg"] finishBlock:nil];

            }
                
            if (code!= NetCode_NETWORK_SUCCESS&&codeError!=nil) {
                dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
                    codeError(code);//這里必須寫,否則tableView在使用本類的時候無法停止刷新搓蚪。一直處于刷新狀態(tài).需要在調用者里面繼續(xù)調用蛤售。
                });
            }
            
        } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
            
            NSString * tips = [NSString stringWithFormat:@"%ld %@",(long)error.code,error.userInfo[@"NSLocalizedDescription"]];
            NSData * data = error.userInfo[@"com.alamofire.serialization.response.error.data"];
            NSString * message = [[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding];
            NSLog(@"服務器的錯誤原因:%@",message);
            [HSCoverView showMessage:tips finishBlock:nil];
            if (fail) {
                fail(error);
            }
        }];
    }
    else if(netSettting.askMethod ==NetMethodGET){
        //調用manage的 GET方法同上
    }
}

公開方法在需要向網(wǎng)絡獲取新數(shù)據(jù)的時候會把自己的所有參數(shù)傳遞給私有方法私有方法在完成網(wǎng)絡請求的時候會把結果回調給公開方法,然后公開方法最終把數(shù)據(jù)返回給調用者。隨著業(yè)務的需求邏輯會愈加復雜悍抑,變動更加多樣鳄炉,需要自己編寫代碼的執(zhí)行邏輯。但是這樣的方法使得在很多情況下僅僅更改某幾行代碼就實現(xiàn)了功能搜骡。

應用場景

  • 為了方便調用拂盯,所有的控制繼承根控制器,根控制器設置了一個HSNetSetting 屬性记靡。并且懶加載的形式重寫了get方法
-(HSNetSetting*)defaultSet
{
      if (_defaultSet == nil) {  
            _defaultSet =[ [HSNetSetting alloc]init];
          //設置默認的配置
       }
      return _defaultSet;
}

這樣所有的子類谈竿,在有tableview的時候發(fā)起網(wǎng)絡請求的時候直接傳遞self.defaultSet 就可以了,而且在 公開方法內部在完成后數(shù)據(jù)請求后摸吠,把傳遞的netSetting改了空凸,如果傳遞的緩存策略是讀緩存,請求完成后直接改成不讀緩存寸痢,不用自己手動更改呀洲。

  • 前段時間啟動頁加廣告,返回的是json啼止,包含了廣告的停留時間和圖片地址道逗,顯示與否信息。但是啟動頁時間太短献烦,本次廣告應該讀取上一次的滓窍,直接在HSNetSetting中加入了
@property (nonatomic,assign) BOOL justReadCache;//啟動頁廣告會用到

然后自己調整緩存方法的邏輯,用同一個方法實現(xiàn)需求巩那。

  • app 不是強制要求用戶登錄的吏夯,但是進行某些功能要登錄。比如:在A界面點擊按鈕Push到B界面即横,但是B界面需要用戶登錄后才能獲得正常信息噪生。否則服務器返回消息提示用戶登錄,所以會在B界面push到登錄頁令境,登錄完成后pop到B界面杠园,然而剛才B頁面沒有數(shù)據(jù),如果不是tableview或者沒有下拉加載功能舔庶,只能返回A抛蚁,然后再push到B界面。用戶體驗很不好惕橙,在網(wǎng)絡封裝方法中提示用戶登錄時加入下面代碼:
HSLoginController * log = [[HSLoginController alloc]init];
log.finishLoginBlock = ^{
          [AFNetworkTool HVJSONDataWithDic:paramDict success:success codeError:codeError fail:fail Setting:netSettting];
                        };
  if (![[HSTool getCurrentVC] isKindOfClass:[HSLoginController class]]) {
            [[HSTool getCurrentVC].navigationController pushViewController:log animated:YES];
    }

給登錄控制器加一個block瞧甩,登錄完成后重新調用一次自己剛剛的操作就能解決這問題。

  • SVProgressHud 網(wǎng)絡請求的時候需要自己總是寫麻煩弥鹦,可以根據(jù)netSetting 配置讓網(wǎng)絡方法內部處理肚逸。但是某些場合不需要出現(xiàn)SVProgressHud爷辙,即使讀取的數(shù)據(jù)是從網(wǎng)絡獲取的也不出現(xiàn),只需要關閉netSetting對SVProgressHud的控制朦促,但是自己也不添加SVProgressHud的控制就時間了膝晾。

  • 緩存時間不由客戶端控制,需要交給服務器控制务冕,無所謂血当,稍微調整網(wǎng)絡方法邏輯就能完成(就是現(xiàn)在這樣的)。

  • 有些界面數(shù)據(jù)更新并不一定是非常頻繁的禀忆,但是需要更新的時候就必須更新臊旭,比如一個界面包含了用戶獲得的積分,在用戶消費了積分后箩退,再次進入這個界面必須刷新數(shù)據(jù)离熏。把這種類型的界面設置不緩存,并且在viewwillappear
    中發(fā)送請求然后刷新UI無疑能解決問題戴涝。但是并不好滋戳,一個是因為請求太頻繁了,浪費流量啥刻,如果數(shù)據(jù)比較多胧瓜,網(wǎng)絡比較慢,用戶體驗很不好郑什。但是通過上面介紹的緩存策略,將緩存時間改成一個極小的值蒲肋,比如1秒蘑拯,就能有效解決問題。因為如果數(shù)據(jù)沒有發(fā)生變化雖然發(fā)起請求兜粘,服務器只返回簡單提示:客戶端的數(shù)據(jù)是最新的申窘,請求的數(shù)據(jù)很快。但是還是不好孔轴。因為數(shù)據(jù)雖然在本地剃法,但是UI還是會刷新一下,就是會閃一下路鹰。解決這樣的問題依然不難贷洲,可以在網(wǎng)絡配置類加一種類型:只要最新的數(shù)據(jù),在本地有緩存的情況下晋柱,僅僅在緩存過期并且數(shù)據(jù)確實發(fā)生變化的時候才把最新的數(shù)據(jù)用success塊回調給控制器优构,當然和前面一樣這里要更新緩存數(shù)據(jù)和日期,其他情況不回調給控制器就解決了雁竞。

到此為止一個相對完整的網(wǎng)絡請求的框架完成钦椭,隨著需求的一步步明確,自己分析的透徹,才有了現(xiàn)在形勢彪腔。其實可以更進一步優(yōu)化侥锦,可以在數(shù)據(jù)庫和數(shù)據(jù)之間在加一層緩存,也許會更好德挣。自己后來看了一本叫做《圖解http協(xié)議》的書恭垦,發(fā)現(xiàn)里面好多緩存策略和上面介紹的很符合,所以以后可以參考下http協(xié)議里面的緩存策略的來擴展網(wǎng)絡類盲厌。


更新:
實現(xiàn)代碼地址:https://github.com/xiaobai1993/HSNetTest署照,以后會逐步完善,減少對當前項目業(yè)務的依賴吗浩。使得通用性更高建芙。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市懂扼,隨后出現(xiàn)的幾起案子禁荸,更是在濱河造成了極大的恐慌,老刑警劉巖阀湿,帶你破解...
    沈念sama閱讀 218,122評論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件赶熟,死亡現(xiàn)場離奇詭異,居然都是意外死亡陷嘴,警方通過查閱死者的電腦和手機映砖,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,070評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來灾挨,“玉大人邑退,你說我怎么就攤上這事±统危” “怎么了地技?”我有些...
    開封第一講書人閱讀 164,491評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長秒拔。 經(jīng)常有香客問我莫矗,道長,這世上最難降的妖魔是什么砂缩? 我笑而不...
    開封第一講書人閱讀 58,636評論 1 293
  • 正文 為了忘掉前任作谚,我火速辦了婚禮,結果婚禮上梯轻,老公的妹妹穿的比我還像新娘食磕。我一直安慰自己,他們只是感情好喳挑,可當我...
    茶點故事閱讀 67,676評論 6 392
  • 文/花漫 我一把揭開白布彬伦。 她就那樣靜靜地躺著滔悉,像睡著了一般。 火紅的嫁衣襯著肌膚如雪单绑。 梳的紋絲不亂的頭發(fā)上回官,一...
    開封第一講書人閱讀 51,541評論 1 305
  • 那天,我揣著相機與錄音搂橙,去河邊找鬼歉提。 笑死,一個胖子當著我的面吹牛区转,可吹牛的內容都是我干的苔巨。 我是一名探鬼主播,決...
    沈念sama閱讀 40,292評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼废离,長吁一口氣:“原來是場噩夢啊……” “哼侄泽!你這毒婦竟也來了?” 一聲冷哼從身側響起蜻韭,我...
    開封第一講書人閱讀 39,211評論 0 276
  • 序言:老撾萬榮一對情侶失蹤悼尾,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后肖方,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體闺魏,經(jīng)...
    沈念sama閱讀 45,655評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,846評論 3 336
  • 正文 我和宋清朗相戀三年俯画,在試婚紗的時候發(fā)現(xiàn)自己被綠了析桥。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,965評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡艰垂,死狀恐怖烹骨,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情材泄,我是刑警寧澤,帶...
    沈念sama閱讀 35,684評論 5 347
  • 正文 年R本政府宣布吨岭,位于F島的核電站拉宗,受9級特大地震影響,放射性物質發(fā)生泄漏辣辫。R本人自食惡果不足惜旦事,卻給世界環(huán)境...
    茶點故事閱讀 41,295評論 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望急灭。 院中可真熱鬧姐浮,春花似錦、人聲如沸葬馋。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,894評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至蛋逾,卻和暖如春集晚,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背区匣。 一陣腳步聲響...
    開封第一講書人閱讀 33,012評論 1 269
  • 我被黑心中介騙來泰國打工偷拔, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人亏钩。 一個月前我還...
    沈念sama閱讀 48,126評論 3 370
  • 正文 我出身青樓莲绰,卻偏偏與公主長得像,于是被迫代替她去往敵國和親姑丑。 傳聞我的和親對象是個殘疾皇子蛤签,可洞房花燭夜當晚...
    茶點故事閱讀 44,914評論 2 355

推薦閱讀更多精彩內容

  • AFHTTPRequestOperationManager 網(wǎng)絡傳輸協(xié)議UDP、TCP彻坛、Http顷啼、Socket、X...
    Carden閱讀 4,337評論 0 12
  • iOS開發(fā)系列--網(wǎng)絡開發(fā) 概覽 大部分應用程序都或多或少會牽扯到網(wǎng)絡開發(fā)昌屉,例如說新浪微博钙蒙、微信等,這些應用本身可...
    lichengjin閱讀 3,661評論 2 7
  • Spring Cloud為開發(fā)人員提供了快速構建分布式系統(tǒng)中一些常見模式的工具(例如配置管理间驮,服務發(fā)現(xiàn)躬厌,斷路器,智...
    卡卡羅2017閱讀 134,657評論 18 139
  • 原文地址:http://casatwy.com/iosying-yong-jia-gou-tan-wang-luo...
    大澎湃閱讀 1,504評論 1 2
  • iOS網(wǎng)絡架構討論梳理整理中竞帽。扛施。。 其實如果沒有APIManager這一層是沒法使用delegate的屹篓,畢竟多個單...
    yhtang閱讀 5,192評論 1 23