iOS开发 取消之前已经发送的Http请求

 

iOS开发中如遇到频繁的Http请求,如何取消之前已经发送的Http请求? 

标签: AFHTTPSessionManagercancelHttpRequestNSURLSessionDataTask取消网络请求

我有一个TextField,无论什么时候当我输入字符的时候,我appending这个字符到我的url,然后发送一次请求,我现在

需要取消之前的请求。例如当我输入“shampoo”的时候,我会触发7次代理方法,也就是我会触发七次不同的网络请

求,那么有一个问题,这七次发出的请求,响应的顺序可不是你想的按顺序返回的,例如发送的是1234567,那么返回

数据很有可能是1234576,这样导致最后需要的结果不是“7”,而是“6”。那么看看我是如何解决的以及遇到坑的!!!


1.第一种解决方案(失败)

[NSObject cancelPreviousPerformRequestsWithTarget:self];

我看到了这个方法,最终测试的结果是,它只能取消掉还未进行网络请求的方法 如下所示

[self performSelector:@selector(startSearchRefresh) withObject:nil afterDelay:0.5];


在这个delay的0.5秒以内,如果我再次触发该方法,那么,第一个方法就会取消掉之前还在delay的方法,从而达到目的

但是如果到了0.5秒,方法已经进行http请求了呢,已经在请求的过程中了呢,这个方法是根本取消不掉的。


因此,这个方法可以用于用户快速输入的时候后一次操作覆盖前一次操作,对我来说还是失败的方法


2.第二种解决方案(失败)

当我进行网络请求的时候

[manager.operationQueue cancelAllOperations]; 

获取到AFNetWorking的对象的时候,拿到它的任务队列,然后取消掉之前所有的任务,我不知道是不是版本的问题,

最新的AF(3.0)以上貌似根本没什么用,也有可能是我的插入方式有问题吧

来看看一个老外的实时搜索的代码段,根本没取消掉

[objc]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. -(BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string;  
  2. {  
  3.   
  4.   
  5.     //[self.s_searchResultText setHidden:YES];  
  6.     // [SVProgressHUD dismiss];  
  7.   
  8.     [self.s_tableView setHidden:true];  
  9.     [searchProductArray removeAllObjects];  
  10.     [self.s_tableView reloadData];  
  11.   
  12.     NSCharacterSet *cs = [[NSCharacterSet characterSetWithCharactersInString:UNACCEPTABLE_CHARACTERS] invertedSet];  
  13.     NSLog(@"%@",cs);  
  14.   
  15.     NSString *filtered = [[string componentsSeparatedByCharactersInSet:cs] componentsJoinedByString:@""];  
  16.     NSLog(@"%@",filtered);  
  17.   
  18.     NSLog(@"%lu",(unsigned long)filtered.length);  
  19.   
  20.     if (filtered.length) {  
  21.         [CustomToastAlert showToastInParentView:self.view withText:@"Please enter valid characters" withDuaration:1.5];  
  22.         return NO;  
  23.     }  
  24.   
  25.   
  26.     searchTextString = [textField.text stringByAppendingString:string];  
  27.     NSLog(@"%lu",(unsigned long)[searchTextString length]);  
  28.   
  29.   
  30.     NSLog(@"%@",searchTextString);  
  31.     int stringLength=[searchTextString length];  
  32.     const charchar * _char = [string cStringUsingEncoding:NSUTF8StringEncoding];  
  33.     int isBackSpace = strcmp(_char, "\b");  
  34.   
  35.     if (isBackSpace == -8) {  
  36.         stringLength=[searchTextString length];  
  37.         stringLength=[searchTextString length]-1;  
  38.         searchTextString=[searchTextString substringToIndex:stringLength];  
  39.         NSLog(@"Backspace was pressed");  
  40.         NSLog(@"string is %@",searchTextString);  
  41.     }  
  42.   
  43.   
  44.   
  45.     if(stringLength>=3)  
  46.     {  
  47.         AFHTTPSessionManager *manager = [[AFHTTPSessionManager alloc] init];  
  48.         manager.responseSerializer = [AFJSONResponseSerializer serializer];  
  49.         NSString *urlString=[NSString stringWithFormat:kSearchProductUrl,kBaseUrl];  
  50.   
  51.         urlString = [urlString stringByAppendingString:searchTextString];  
  52.         urlString = [urlString stringByReplacingOccurrencesOfString:@" " withString:@"%20"];  
  53.   
  54.         NSLog(@"%@",searchTextString);  
  55.         NSLog(@"%@",urlString);  
  56.         [searchProductArray removeAllObjects];  
  57.        // [manager invalidateSessionCancelingTasks:NO];  
  58.         //[manager.operationQueue cancelAllOperations];  
  59.   
  60.   
  61.         [manager GET:urlString parameters:nil success:^(NSURLSessionDataTask *task, id responseObject)  
  62.          {  
  63.              [searchProductArray removeAllObjects];  
  64.   
  65.              //[SVProgressHUD showWithStatus:LOADING_ITEMS maskType:SVProgressHUDMaskTypeGradient];  
  66.              NSLog(@"JSON: %@", responseObject);  
  67.              json= responseObject;  
  68.              NSLog(@"%@",json);  
  69.              NSLog(@"%lu",(unsigned long)[[json valueForKeyPath:@"data"] count ]);  
  70.   
  71.              for(int i=0;i<[[json valueForKeyPath:@"data"]count ];i++)  
  72.              {  
  73.                  Product *s_productList=[[Product alloc]init];  
  74.                  s_productList.SKU_Name=[[json valueForKeyPath:@"data.sku_name"]objectAtIndex:i];  
  75.                  s_productList.SKU_Id=[[json valueForKeyPath:@"data.sku_id"]objectAtIndex:i];  
  76.                  s_productList.SKU_Price=[[json valueForKeyPath:@"data.sku_price"]objectAtIndex:i];  
  77.                  s_productList.SKU_OfferPrice=[[json valueForKeyPath:@"data.sku_offer_price"]objectAtIndex:i];  
  78.   
  79.                  s_productList.SKU_Currency = RUPEE_SYMBOL;  
  80.                  s_productList.SKU_AvailableUnit=[[json valueForKeyPath:@"data.sku_available_unit"]objectAtIndex:i];  
  81.                  s_productList.SKU_OfferDescription= [[json valueForKeyPath:@"data.sku_offer_desc"]objectAtIndex:i];  
  82.                  s_productList.SKU_ImageUrls=[[json valueForKeyPath:@"data.sku_image_urls"]objectAtIndex:i];  
  83.   
  84.   
  85.                  [searchProductArray addObject:s_productList];  
  86.                  NSLog(@"%lu",(unsigned long)[searchProductArray count]);  
  87.   
  88.   
  89.              }  
  90.              [self.s_tableView setHidden:FALSE];  
  91.              [self.s_tableView reloadData];  
  92.              NSLog(@"%lu",(unsigned long)[searchProductArray count]);  
  93.              if ([searchProductArray count]==0) {  
  94.                  [CustomToastAlert showToastInParentView:self.view withText:SEARCH_RESULT withDuaration:1.5];  
  95.   
  96.   
  97.   
  98.              }  
  99.   
  100.   
  101.          }  
  102.   
  103.              failure:^(NSURLSessionDataTask *task, NSError *error)  
  104.          {  
  105.              [CustomToastAlert showToastInParentView:self.view withText:NO_DATA_AVAIL withDuaration:1.5];  
  106.          }];  
  107.   
  108.   
  109.     }  
  110.   
  111.     return YES;  
  112.   
  113. }  

3.第三种解决方法,这个才是我最终的解决方案

该方法也是从stackOverFlow上找来的,真的是找死我了

以上面的代码段为例,他是这么操作的

主要精髓在于

第一点:不要initialize a new AFHTTPSessionManager object everytime 一定要把manager用成全局的

第二点:把请求返回的task对象丢进数组,下次触发的时候把遍历数组,把之前的所有任务[task cancel]

[objc]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. // somewhere in your class, let's say in ViewDidLoad you should init the AFHTTPSessionManager object  
  2. - (void)viewDidLoad {  
  3.     [super viewDidLoad];  
  4.   
  5.     /// create the AFHTTPSessionManager object, we're gonna use it in every request  
  6.     self.manager = [[AFHTTPSessionManager alloc] init];  
  7.     self.manager.responseSerializer = [AFJSONResponseSerializer serializer];  
  8.   
  9.     /// create an array that is going to hold the requests task we've sent to the server. so we can get back to them later  
  10.     self.arrayOfTasks = [NSMutableArray new];  
  11.     /// discussion:  
  12.     /// an array holds multiple objects. if you just want to hold a ref to the latest task object  
  13.     /// then create a property of NSURLSessionDataTask instead of NSMutableArray, and let it point to the latest NSURLSessionDataTask object you create  
  14.   
  15. }  
  16.   
  17.   
  18.   
  19. -(BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string;{  
  20.     /// your code goes here  
  21.     /// .....  
  22.     /// .....  
  23.     /// .....  
  24.     /// .....  
  25.     /// till we reach  
  26.     if(stringLength>=3){  
  27.         /// cancel all previous tasks  
  28.         [self.arrayOfTasks enumerateObjectsUsingBlock:^(NSURLSessionDataTask *taskObj, NSUInteger idx, BOOLBOOL *stop) {  
  29.             [taskObj cancel]; /// when sending cancel to the task failure: block is going to be called  
  30.         }];  
  31.   
  32.         /// empty the arraOfTasks  
  33.         [self.arrayOfTasks removeAllObjects];  
  34.   
  35.         /// init new task  
  36.         NSURLSessionDataTask *task = [self.manager GET:urlString parameters:nil success:^(NSURLSessionDataTask *task, id responseObject){  
  37.            /// your code  
  38.         }failure:^(NSURLSessionDataTask *task, NSError *error){  
  39.            /// your code  
  40.         }];  
  41.   
  42.         /// add the task to our arrayOfTasks  
  43.         [self.arrayOfTasks addObject:task];  
  44.     }  
  45.     return YES;  
  46. }  

注意:

这里的task cancel亲测确实能把网络请求cancel掉,可以看下面的log,记住一点,这里cancel之后不代表就不回调

了,只是会回调到error的那个block里面,各位需要信息的可以测试下,在error打个断点就能调试出来了

[objc]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. // 查看网络任务的状态  
  2. [articleInterface.articleArrayTask enumerateObjectsUsingBlock:^(NSURLSessionDataTask *taskObj, NSUInteger idx, BOOLBOOL *stop) {  
  3.     DDLogVerbose(@"当前的文章删除前网络任务状态是==================>>>>>%ld",taskObj.state);  
  4.     [taskObj cancel]; /// when sending cancel to the task failure: block is going to be called  
  5.     DDLogVerbose(@"当前的文章删除后网络任务状态是==================>>>>>%ld",taskObj.state);  
  6. }];  
  7. typedef NS_ENUM(NSInteger, NSURLSessionTaskState) {  
  8.     NSURLSessionTaskStateRunning = 0,                     /* The task is currently being serviced by the session */  
  9.     NSURLSessionTaskStateSuspended = 1,  
  10.     NSURLSessionTaskStateCanceling = 2,                   /* The task has been told to cancel.  The session will receive a URLSession:task:didCompleteWithError: message. */  
  11.     NSURLSessionTaskStateCompleted = 3,                   /* The task has completed and the session will receive no more delegate notifications */  
  12. } NS_ENUM_AVAILABLE(NSURLSESSION_AVAILABLE, 7_0);  


打印日志  这里的2代表NSURLSessionTaskStateCanceling





ok,圆满解决

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值