iOS 如何避免在短時(shí)間內(nèi)頻繁發(fā)出相同的網(wǎng)絡(luò)請(qǐng)求?

  1. UI控制

    這種控制在下拉刷新時(shí)體現(xiàn)的比較明顯。觀察下拉刷新框架時(shí)我們會(huì)發(fā)現(xiàn)下拉觸發(fā)網(wǎng)絡(luò)請(qǐng)求后,界面UI會(huì)處于一個(gè)刷新狀態(tài),直到此次的請(qǐng)求成功或失敗時(shí)界面才會(huì)恢復(fù)至常態(tài),此時(shí)界面才支持下一次的刷新,這樣的控制保證了短時(shí)間內(nèi)只有一個(gè)請(qǐng)求在運(yùn)行。


    新浪微博的下拉刷新
  2. 根據(jù)需求只保留第一次發(fā)出的請(qǐng)求

這種情況多發(fā)生在點(diǎn)擊一個(gè)按鈕之后要發(fā)送一個(gè)請(qǐng)求,而且每次的請(qǐng)求攜帶的參數(shù)是相同的,即每次發(fā)送出去的都是同一個(gè)請(qǐng)求,此時(shí)我們根據(jù)需要只保留第一次發(fā)送出去的請(qǐng)求即可。

  1. 根據(jù)需求只保留最后一次發(fā)出的請(qǐng)求

這種情況相對(duì)于第二種情況的差別是每次的請(qǐng)求攜帶的參數(shù)是不同的,比如搜索時(shí),在用戶的每次輸入后都會(huì)主動(dòng)觸發(fā)請(qǐng)求,用戶輸入的文字會(huì)作為一個(gè)參數(shù),如果用戶慢速地依次輸入c、cc、ccc時(shí)我們發(fā)現(xiàn)搜索的提示信息是會(huì)跟隨著輸入的內(nèi)容發(fā)生改變的。假設(shè)每次輸入都會(huì)觸發(fā)網(wǎng)絡(luò)請(qǐng)求,在用戶快速輸入的時(shí)候,如果對(duì)網(wǎng)絡(luò)請(qǐng)求不做處理時(shí)會(huì)發(fā)生這樣一種情況,因?yàn)檎?qǐng)求是異步的,很有可能我們最后展示的網(wǎng)絡(luò)返回信息并不是最后一次發(fā)送出的請(qǐng)求返回來的。這種情況我們就要根據(jù)需求只保留最后一次發(fā)出的請(qǐng)求即可。

輸入c

輸入cc

基于AFNetworking框架,我找到了實(shí)現(xiàn)情況2、3的方法。先看效果

for (int i = 0; i < 20; i++) {
    [Weather loadWeatherInformationWithCallBack:^(NSArray *array, NSError *error) {
        if (error) {
            NSLog(@"%@", error);
            return;
        } else {
            self.testArray = [self.testArray arrayByAddingObjectsFromArray:array];
            self.weather = self.testArray;
            NSLog(@"-------------------------%d", i);
        }
    } keepFirst:NO];
 }

我們?cè)诳刂破髦杏胒or循環(huán)發(fā)出20個(gè)請(qǐng)求,如果keepFirst參數(shù)為NO,控制臺(tái)輸出為:

保留最后一次請(qǐng)求

如果keepFirst參數(shù)為YES,控制臺(tái)輸出為:

保留第一次請(qǐng)求

網(wǎng)絡(luò)單例中的代碼如下:

// 加載天氣信息,并以keepFirst參數(shù)來標(biāo)示是否保留第一次的請(qǐng)求
- (void)loadWeatherInformationWithCallBack:(callBack)callBack keepFirst:(BOOL)isKeepFirst {
    NSString *string = @"data/sk/101180101.html";
    [self requestMethod:@"GET" URLString:string params:nil finish:callBack keepFirst:isKeepFirst];
}

// get和post的封裝
- (void)requestMethod:(NSString *)method URLString:(NSString *)string params:(NSDictionary *)params finish:(callBack)callBack keepFirst:(BOOL)isKeepFirst {
    
    // 成功回調(diào)
    void(^successBlock)(NSURLSessionDataTask *, id) = ^(NSURLSessionDataTask *task, id responseObject) {
        // 清除緩存
        [self.datas removeObjectForKey:string];
        if (responseObject) {
            callBack(responseObject, nil);
        } 
    };
    // 失敗回調(diào)
    void(^failBlock)(NSURLSessionDataTask *, NSError *) = ^(NSURLSessionDataTask *task, NSError *error) {
        // 清除緩存
        [self.datas removeObjectForKey:string];

        // 如果是我們主動(dòng)調(diào)用  [originalTask cancel]; 的話會(huì)立即返回到失敗的回調(diào)中,且error中的一個(gè)字段會(huì)被標(biāo)示為`cancelled`,我們以此來過濾掉取消的task的回調(diào)。
        if ([error.userInfo[@"NSLocalizedDescription"] isEqualToString:@"cancelled"]) {
            return;
        }
        callBack(nil, error);
    };
    
    NSURLSessionDataTask *originalTask = [self.datas objectForKey:string];

    // 如果保留第一次請(qǐng)求,且存在初始請(qǐng)求,return
    if (isKeepFirst && originalTask) {
        return;
    }
    
    [originalTask cancel];
    NSURLSessionDataTask *task = nil;
    if ([method isEqualToString:@"GET"]) {
        task = [self GET:string parameters:params success:successBlock failure:failBlock];
    }
    if ([method isEqualToString:@"POST"]) {
        task = [self POST:string parameters:params success:successBlock failure:failBlock];
    }
    // 網(wǎng)絡(luò)單例中會(huì)用一個(gè)字典屬性來存儲(chǔ)網(wǎng)絡(luò)請(qǐng)求,為加以區(qū)分以每個(gè)請(qǐng)求的`url` 做為 key 進(jìn)行存儲(chǔ)
    [self.datas setValue:task forKey:string];
}

完整的項(xiàng)目已經(jīng)上傳到github上了項(xiàng)目地址

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,569評(píng)論 19 139
  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 179,063評(píng)論 25 709
  • iOS網(wǎng)絡(luò)架構(gòu)討論梳理整理中。。。 其實(shí)如果沒有APIManager這一層是沒法使用delegate的,畢竟多個(gè)單...
    yhtang閱讀 5,490評(píng)論 1 23
  • 分類(category)在iOS開發(fā)中的應(yīng)用非常廣泛, 優(yōu)點(diǎn)譬如給現(xiàn)有的類拓展更多的方法、對(duì)一個(gè)類的多種功能進(jìn)行局...
    zzysummer閱讀 1,005評(píng)論 0 0

友情鏈接更多精彩內(nèi)容