Как найти и отменить задачу в NSURLSession?

Я использую объект NSURLSession для загрузки изображений в свое приложение. Это может быть загрузка нескольких изображений одновременно.

В некоторые моменты мне нужно отменить загрузку одного конкретного изображения и продолжить загрузку других.

Не могли бы вы предложить правильный способ сделать это?


person Rostyslav Druzhchenko    schedule 07.05.2014    source источник
comment
Ну, есть NSURLSessionTask API, найдите то, что вы хотите отменить, и вызовите на него cancel.   -  person esh    schedule 07.05.2014
comment
Правильно, это NSURLSesstionTask и его легко отправить cancel методом. Но проблема найти конкретную задачу. В этом случае мне нужно перечислить все задачи текущего сеанса и найти нужную мне задачу по описанию, например. Итак, мне нужен способ перечислить задачи в сеансе.   -  person Rostyslav Druzhchenko    schedule 07.05.2014


Ответы (6)


Чтобы получить список задач, вы можете использовать метод NSURLSession.

- (void)getTasksWithCompletionHandler:(void (^)(NSArray *dataTasks, NSArray *uploadTasks, NSArray *downloadTasks))completionHandler;

Асинхронно вызывает обратный вызов завершения со всеми невыполненными данными, загрузкой и загрузкой задач в сеансе.

Затем проверьте task.originalRequest.URL возвращенные задачи, чтобы найти ту, которую вы хотите отменить.

person Avt    schedule 07.05.2014
comment
Вы можете просмотреть раздел Obtaining General Task Information в это. А затем идентифицируйте свой запрос через эти средства и отмените задачу в блоке, включенном в этот метод. - person esh; 08.05.2014
comment
Это странно, в Xcode 6, iOS 8 и Swift я получаю нераспознанный селектор, когда вызываю invalidateAndCancel() для объекта dataTask. - person Van Du Tran; 27.11.2014
comment
@VanDuTran Вы должны использовать метод «отмены» developer.apple.com/library/ios/documentation/Foundation/ - person Avt; 02.12.2014

Надеюсь, что код ниже поможет.

-(IBAction)cancelUpload:(id)sender {    
    if (_uploadTask.state == NSURLSessionTaskStateRunning) {
        [_uploadTask cancel];
     }
  }
person annu    schedule 11.03.2015

Основываясь на всех приведенных ниже ответах, я бы выбрал что-то вроде этого:

Свифт 5

 func cancelTaskWithUrl(_ url: URL) {
    URLSession.shared.getAllTasks { tasks in
      tasks
        .filter { $0.state == .running }
        .filter { $0.originalRequest?.url == url }.first?
        .cancel()
    }
  }

Вы также, вероятно, захотите учитывать обработчик завершения задачи, поскольку отмена задачи приведет к Error в этом обработчике завершения.

person inokey    schedule 08.10.2019
comment
Спасибо за ваше предложение @inokey. .filter { $0.state == .running } можно опустить. Поскольку в документации указано The arrays passed to the completion handler contain any tasks that you have created within the session, not including any tasks that have been invalidated after completing, failing, or being cancelled. - person Rostyslav Druzhchenko; 08.10.2019

Swift 3.0 версия ответа @Avt, чтобы получить список задач. Используйте getTasksWithCompletionHandler.

func getTasksWithCompletionHandler(_ completionHandler: @escaping ([URLSessionDataTask], 
   [URLSessionUploadTask], 
   [URLSessionDownloadTask]) -> Void) {     
}

Возвращаемые массивы содержат все задачи, созданные вами в рамках сеанса, за исключением задач, признанных недействительными после завершения, сбоя или отмены.

person pedrouan    schedule 23.09.2016
comment
Я проголосовал за это, так что, надеюсь, оно попадет в топ, так как правильно было сделать это, не сохраняя список вручную. - person Jimbo; 22.02.2018

Я предлагаю два метода:

  1. Поместите список NSURLSessionTask в массив. Если вы точно не знаете, сколько изображений вы получите. Хотя вам нужно знать индекс сеанса, чтобы отменить его.
  2. Если вы получаете ограниченное количество изображений. Просто используйте набор NSURLSessionTask в качестве глобальных переменных, чтобы вы могли отменить его в любом месте вашего класса.
person Thanh-Nhon Nguyen    schedule 07.05.2014
comment
Спасибо за ваш ответ, но я считаю, что это немного грубо. Оба они будут работать, но у обоих есть проблемы с программным обеспечением, такие как использование глобальных переменных и дублирование. Их можно использовать, если не существует правильного пути. - person Rostyslav Druzhchenko; 07.05.2014

Я думаю, ты должен сделать это...

Во-первых, следите за своими запросами на xib

var download_requests = [NSURLSession]()

Затем, всякий раз, когда вы делаете запрос, добавляйте свой запрос в свой массив следующим образом:

let s = NSURLSession(configuration: NSURLSessionConfiguration.defaultSessionConfiguration())
if let url = NSURL(string: "http://my.url.request.com")
{
  download_requests.append(s)
  s.dataTaskWithURL(url)
  { (data, resp, error) -> Void in
    // ....
  }
}

Затем, когда вы хотите отменить любые невыполненные запросы (скажем, на viewDidDisappear), выполните

  override func viewDidDisappear(animated: Bool)
  {
    super.viewDidDisappear(animated)
    //stop all download requests
    for request in download_requests
    {
      request.invalidateAndCancel()
    }
  }
person Who Is The Baddest    schedule 22.11.2015
comment
Вам не нужно сохранять сеансы, посмотрите ответ @pedrouan - person Jimbo; 22.02.2018
comment
Вау, этот ответ все еще работает в Swift 5.2 - person Ketan Odedra; 14.12.2020