【问题标题】:URLSession Cancellation in swift while auto search自动搜索时快速取消 URLSession
【发布时间】:2017-02-08 04:21:11
【问题描述】:

我的 moto 是自动搜索,我一直在尝试使用 URLSession,当我尝试缓慢搜索时,请求按预期处理(当没有文本时,响应为空,我的意思是 placesarray)但是当我试图清除文本或快速点击任何搜索文本,然后将先前的请求响应附加到位置数组中。我尝试取消先前的请求但我没有得到结果(即未附加先前的响应)

func autoSearch(text:String){    
   let urlRequest = URLRequest(url: self.getQueryFormedBingURL()!)

   let session = URLSession.shared
   session.getTasksWithCompletionHandler
   {
      (dataTasks, uploadTasks, downloadTasks) -> Void in
      // self.cancelTasksByUrl(tasks: dataTasks     as [URLSessionTask])
      self.cancelTasksByUrl(tasks: uploadTasks   as [URLSessionTask])
      self.cancelTasksByUrl(tasks: downloadTasks as [URLSessionTask])
   }
   let task = session.dataTask(with: urlRequest, completionHandler: { (data, response, error) -> Void in

   print("response \(response)")

   if let data = data {

      let json = try? JSONSerialization.jsonObject(with: data, options: [])

      if let response = response as? HTTPURLResponse , 200...299 ~= response.statusCode {

         if let jsonDic = json as? NSDictionary {

             let status = jsonDic.returnsObjectOrNone(forKey: "statusCode") as! Int

              if status == 200 {

                 if let resourceSetsArr = jsonDic.returnsObjectOrNone(forKey: "resourceSets") as? NSArray {

                    if let placesDict = resourceSetsArr.object(at: 0) as? NSDictionary {
                       if let resourceArr = placesDict.object(forKey: "resources") as? NSArray, resourceArr.count > 0 {

                          if let _ = self.placesArray {
                             self.placesArray!.removeAll()
                          }
                          for loopCounter in 0...resourceArr.count - 1 {
                             let modalClass:BingAutoCompletePlace = BingAutoCompletePlace(responseDict: resourceArr[loopCounter] as! NSDictionary)
                             self.placesArray?.append(modalClass)
                          }
                          completion(self.placesArray!)
                       }
                       else { //URL Success, where there no places with the given search string
                          completion([])
                       }
                    }
                 }
              }
           }
        }
        else if let response = response as? HTTPURLResponse , 400...499 ~= response.statusCode {// When url fails
                if let _ = error {
                   print("error=\(error!.localizedDescription)")
                }
                completion([])
             }
             else {
                if let _ = error {
                   print("error=\(error!.localizedDescription)")
                }
                completion([])
             }
         }
     })
     task.resume()
}

//请求取消

private func cancelTasksByUrl(tasks: [URLSessionTask]) {
   for task in tasks
   {
      task.cancel()
   }
}

【问题讨论】:

    标签: ios swift swift3 nsurlsession nsurlsessiondownloadtask


    【解决方案1】:

    不幸的是,框架不保证任务完成的任何顺序——因为这取决于运行时间。也可能是您处于当前已取消任务的完成处理程序中。

    要避免这种情况,您可以执行以下操作:

    • 创建一个私有实例变量来存储最近的任务
    • 像以前一样取消其他所有内容
    • 在完成处理程序中
      • 检查任务是否仍然是最近的任务(如if (task !== self.currentTask) {return})
      • 创建一个本地数组来存储数据
      • 在主线程中更新视图控制器数组 (DispatchQueue.main.async(...))

    我清理了你的代码(使用guard 语句来最小化嵌套)。也许你也应该

    • 在所有错误/空的情况下清空数组(而不是简单地从guard 语句返回)
    • 将任务交给completion 调用并再次检查该任务是否仍然是当前任务。这也是将currentTask 重置为nil 的好方法。

    根据您的需要采用它 :-)

    var currentTask:URLSessionDataTask?
    
    func autoSearch(text:String){
        let completion:(_ x:[AnyObject])->() =  {_ in }
    
        let urlRequest = URLRequest(url: self.getQueryFormedBingURL()!)
    
        let session = URLSession.shared
        session.getTasksWithCompletionHandler
            {
                (dataTasks, uploadTasks, downloadTasks) -> Void in
                //                self.cancelTasksByUrl(tasks: dataTasks     as [URLSessionTask])
                self.cancelTasksByUrl(tasks: uploadTasks   as [URLSessionTask])
                self.cancelTasksByUrl(tasks: downloadTasks as [URLSessionTask])
        }
    
        var task:URLSessionDataTask!
        task = session.dataTask(with: urlRequest, completionHandler: { (data, response, error) -> Void in
    
            print("response \(response)")
    
            if (task !== self.currentTask) {
                print("Ignore this task")
                return
            }
    
            if let error = error {
                print("response error \(error)")
            }
    
            guard let data = data else { return }
    
            let json = try? JSONSerialization.jsonObject(with: data, options: [])
    
            var newPlacesArray = [AnyObject]() // Empty array of whichever type you want
    
            if let response = response as? HTTPURLResponse , 200...299 ~= response.statusCode {
    
                guard let jsonDic = json as? NSDictionary else { return }
    
                let status = jsonDic.returnsObjectOrNone(forKey: "statusCode") as! Int
    
                if status == 200 {
    
                    guard let resourceSetsArr = jsonDic.returnsObjectOrNone(forKey: "resourceSets") as? NSArray else { return }
                    guard let placesDict = resourceSetsArr.object(at: 0) as? NSDictionary else { return }
                    guard let resourceArr = placesDict.object(forKey: "resources") as? NSArray, resourceArr.count > 0 else {
                        //URL Success, where there no places with the given search string
                        DispatchQueue.main.async {completion(newPlacesArray)}
                        return
                    }
    
                    for loopCounter in 0...resourceArr.count - 1 {
                        let modalClass:BingAutoCompletePlace = BingAutoCompletePlace(responseDict: resourceArr[loopCounter] as! NSDictionary)
                        newPlacesArray.append(modalClass)
                    }
                    DispatchQueue.main.async {completion(newPlacesArray)}
                }
            }
            else if let response = response as? HTTPURLResponse , 400...499 ~= response.statusCode {// When url fails
                if let _ = error {
                    print("error=\(error!.localizedDescription)")
                }
                DispatchQueue.main.async {completion(newPlacesArray)}
            }
            else {
                if let _ = error {
                    print("error=\(error!.localizedDescription)")
                }
                DispatchQueue.main.async {completion(newPlacesArray)}
            }
        })
    
        self.currentTask = task
        task.resume()
    }
    

    【讨论】:

      猜你喜欢
      • 2015-03-20
      • 1970-01-01
      • 2014-12-27
      • 1970-01-01
      • 2018-10-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-08-20
      相关资源
      最近更新 更多