1. 程式人生 > >iOS網路請求太頻繁 處理之前傳送的http請求(取消)

iOS網路請求太頻繁 處理之前傳送的http請求(取消)

搜尋功能在APP中非常的常見,搜尋功能伴隨的往往是實時搜尋結果,極大的方便了使用者的查詢與實時資料的更新,但是也有極大的問題,當我們搜尋框的文字改變的時候,就會進行網路請求,如果輸入特別快的時候,網路請求也會特頻繁,對伺服器的壓力也就更大。

解決方法:在進行新的網路請求的時候,把之前的http請求取消掉,保證同一時間只有一個http請求在執行,這樣就極大的優化了效能,同時減小了伺服器的壓力

下面我們用常用的網路請求第三方-----AFNetWorking為例簡單明瞭的演示一下

大致思路:宣告一個全域性的 AFHTTPSessionManager *manager;再宣告一個全域性的可變陣列用於存放 http請求。

PS:進行http請求的時候,一定要建立一個新的 NSURLSessionDataTask 任務

再PS:[task cancel]之後,並不是說這個http請求就完全沒有任何音訊了,task會立刻回掉 error,NSLog(@"error:%@",error.description);可以列印log訊息看到Code=-999 “已取消”

上程式碼

#import "LPDemoVC.h"

#import <AFNetworking.h>

@interface LPDemoVC ()

@property (nonatomic,strong)    AFHTTPSessionManager    *manager;
@property (nonatomic,strong)    NSMutableArray          *taskArray;

@end

@implementation LPDemoVC

#pragma mark -- taskArr
-(NSMutableArray *)taskArray{
    if (!_taskArray) {
        _taskArray = [NSMutableArray arrayWithCapacity:3];
    }
    return _taskArray;
}

- (void)viewDidLoad {
    [super viewDidLoad];
    //初始化  AFHTTPSessionManager 並且設定配置資訊,在這不做多述
    self.manager = [AFHTTPSessionManager manager];
    self.manager.responseSerializer = [AFHTTPResponseSerializer serializer];
    
}

-(BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string{
    //獲取當前輸入字串,並且呼叫網路資料
    NSString *searchStr = [textField.text stringByReplacingCharactersInRange:range withString:string];
    [self loadDataWithSearchStr:searchStr];
    return YES;
}

-(void)loadDataWithSearchStr:(NSString *)searchStr{
    //首先遍歷存放task的陣列,並且取消之前的http請求
    [self.taskArray enumerateObjectsUsingBlock:^(NSURLSessionDataTask *task, NSUInteger idx, BOOL * _Nonnull stop) {
        NSLog(@"這個任務取消之前的狀態是:::::%ld",task.state);
        [task cancel];//取消http請求
        NSLog(@"這個任務取消之後的狀態是:::::%ld",task.state);
    }];
    //移除self.taskArray中所有的任務
    [self.taskArray removeAllObjects];
    //建立一個新的NSURLSessionDataTask,記住,一定是新建立一個任務
    NSURLSessionDataTask *newTask = [self.manager GET:@"你的介面url" parameters:nil progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
        NSDictionary *JSON = [NSJSONSerialization JSONObjectWithData:responseObject options:NSJSONReadingMutableContainers error:nil];
        NSLog(@"success:%@",JSON);
        //在這裡處理資料
        
        
    } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
        NSLog(@"error:%@",error.description);
    }];
    //把最新的任務存進self.taskArray,用於下次遍歷
    [self.taskArray addObject:newTask];
}

/*
#pragma mark - Navigation

// In a storyboard-based application, you will often want to do a little preparation before navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
    // Get the new view controller using [segue destinationViewController].
    // Pass the selected object to the new view controller.
}
*/

@end

這裡給出NSURLSessionTaskState的狀態碼

typedef NS_ENUM(NSInteger, NSURLSessionTaskState) {
    NSURLSessionTaskStateRunning = 0,                     /* The task is currently being serviced by the session */
    NSURLSessionTaskStateSuspended = 1,
    NSURLSessionTaskStateCanceling = 2,                   /* The task has been told to cancel.  The session will receive a URLSession:task:didCompleteWithError: message. */
    NSURLSessionTaskStateCompleted = 3,                   /* The task has completed and the session will receive no more delegate notifications */
} NS_ENUM_AVAILABLE(NSURLSESSION_AVAILABLE, 7_0);

搞定!!!