-
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)行。
新浪微博的下拉刷新 根據(jù)需求只保留第一次發(fā)出的請(qǐng)求
這種情況多發(fā)生在點(diǎn)擊一個(gè)按鈕之后要發(fā)送一個(gè)請(qǐng)求,而且每次的請(qǐng)求攜帶的參數(shù)是相同的,即每次發(fā)送出去的都是同一個(gè)請(qǐng)求,此時(shí)我們根據(jù)需要只保留第一次發(fā)送出去的請(qǐng)求即可。
- 根據(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)求即可。
基于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)輸出為:

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

網(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)目地址