2016-04-29 3 views
4

Быстрый вопрос.Отменить блок завершения

Обычно мы делаем веб-вызова и получения ответа, мы возвращаем данные в блоке завершения, как показано ниже

func someAPIcall(input: input, completion: (result: data) -> Void) { 
    ... 
    completion(data) 
} 

и я использовать функции, как показано ниже

someAPIcall(input) { 
    (result: data) in 
    print(result) 
    // Update UI, etc 
} 

Является ли это можно каким-то образом отменить блокировку завершения? Скажем, если я немедленно сделаю веб-звонок и popViewController, хотя если я отменил request, если данные будут возвращены блоку завершения, будет выполнена задача завершения.

Есть ли какой-либо механизм, с помощью которого я мог бы назначить var закрытию и мог бы отменить его позже?

Как я могу отменить блок от выполнения, когда потребуется, скажем, в viewWillDisappear?

+0

как вы сохраняете блок завершения и отменяете действие? – Wain

+0

Я спрашиваю, возможно ли это сделать .. Чтобы отменить действие закрытия закрытия. – iOS

+0

не отменить блок завершения после его запуска, вам не нужно вызывать блок завершения ... – Wain

ответ

1

0 Да, нет ничего, что позволяло бы отменить любой блок. Таким образом, блок будет выполнять команду при ее вызове. Тем не менее, блок может, конечно, выполнять код, который определяет, требуется ли какое-либо действие, которое оно должно было выполнить.

Часто у вас будет небольшая ссылка на какой-либо объект в вашем блоке и не выполнять действие, если эта слабая ссылка равна нулю. В других случаях вы можете проверить какое-либо свойство объекта. Прямой метод, который всегда работает: Создайте тривиальный класс с единственным свойством экземпляра «отменено». Создайте и получите экземпляр экземпляра, пусть блок ссылается на него, если вы хотите отменить блок, установите для свойства «отменено» значение «истина», и обратный вызов проверяет этот параметр. (Опять же, вы можете сделать его слабым, и если вызывающий пользователь больше не интересуется, он может просто отпустить этот экземпляр).

2

Я предполагаю, что вы сильно сохраняете себя в блоке завершения. Если вы передадите слабую ссылку на себя в списке захвата, ваши действия не будут выполняться, если диспетчер представлений будет выпущен.

someAPIcall(input) { [weak self] result in 
    guard let strongSelf = self else { return } 

    strongSelf.label.text = ... 
} 

Примечание. Это будет работать только в том случае, если задачи, выполняемые вами в блоке, выполняются самостоятельно. someAPIcall все еще поддерживает ссылку на блок завершения, но блок завершения имеет слабую ссылку на ваш контроллер представления. (Технически вы можете использовать значение слабого «я» для проверки выполнения других задач).

Если этого недостаточно, и у вас есть доступ к реализации someAPIcall, то вы можете добавить метод cancel() (как уже упоминалось), чем остановит вызов, и освободить блок.

5

Вы не можете обязательно удалить блок завершения из существования, но так как это ваш блок завершения, вы можете легко просто ничего не делать, когда его называют:

func someAPIcall(input: input, completion: (result: data) -> Void) { 
    guard somethingOrOther else {return} 
    // ... 
    completion(data) 
} 

somethingOrOther может быть свойством self, или (как вы уже сказали), вы можете проверить, существует ли еще self.

Это не очень отличается от механизма, используемого NSOperation, который может проверить свой собственный объект cancelled, прежде чем что-либо делать.

0

Существует много разных способов сделать это. Правильный ответ зависит от вашего конкретного варианта использования и того, как вы разработали взаимодействие с API. У NSOperations есть отличный рабочий процесс управления отменой/зависимостью/завершения, поэтому, если вы можете разместить свои взаимодействия с API в NSOperationQueue, это может быть наилучшим способом продвижения вперед. Еще одна возможность, которую я использую для некоторых более простых взаимодействий, - просто сохранить ссылку на NSURLSessionTasks, которые соответствуют определенному взаимодействию просмотра представления контроллера, и отменить их по мере необходимости. Например:

//: Playground - noun: a place where people can play 

import UIKit 

class MyViewController: UIViewController, UISearchBarDelegate { 

    var tasks = [NSURLSessionTask]() 
    let client = MyAPIClient() 

    deinit { 
     cancelAllTasks() 
    } 

    func cancelAllTasks() { 
     tasks.forEach { $0.cancel() } 
    } 

    func cancelAllSearchTasks() { 
     tasks.filter({ $0.taskDescription == MyAPIClient.TaskDecription.search.rawValue }).forEach { $0.cancel() } 
    } 

    func searchBar(searchBar: UISearchBar, textDidChange searchText: String) { 
     // Cancel previous search as user types a new search 
     cancelAllSearchTasks() 

     guard let text = searchBar.text else { 
      return 
     } 

     tasks.append(client.search(text) { [weak self] results in 
      // ... 
     }) 
    } 

} 

class MyAPIClient { 

    enum TaskDecription: String { 
     case search 
    } 

    let session = NSURLSession() 

    func search(text: String, completion: (result: [String]) -> Void) -> NSURLSessionTask { 
     let components = NSURLComponents() 
     components.scheme = "http" 
     components.host = "myapi.com" 
     components.queryItems = [NSURLQueryItem(name: "q", value: text)] 
     guard let url = components.URL else { 
      preconditionFailure("invalid search url") 
     } 

     let task = session.dataTaskWithURL(url) { (data, response, error) in 
      // ... 
      completion(result: ["results", "from", "api", "go", "here!"]) 
     } 
     task.resume() 
     task.taskDescription = TaskDecription.search.rawValue 

     return task 
    } 
} 

Здесь, когда контроллер зрения освобождаться, мы отменяем все NSURLSessionTasks, которые связаны с этим контроллером. Мы также отменяем любые существующие «поисковые» задачи api, поскольку пользователь вводит в панель поиска, чтобы мы не делали «устаревшие» вызовы api.

Конечно, это довольно простой пример, но вы получаете идею - хорошо быть умным в отношении количества сетевых звонков, которые делает ваше приложение, и отменить их, если они больше не нужны!

Смежные вопросы