Как отменить зависимые операции - PullRequest
0 голосов
/ 02 октября 2018

См. Правку внизу.Я считаю, что ссылка, которую я разместил там, отвечает на мой вопрос.

Я пишу приложение для iOS, которое требует доступа к камере и местоположению, чтобы пользователь мог сделать снимок и сохранить его с помощью CLLocation, где была сделана фотография.Я решил реализовать архитектуру на основе операций, в которой я создаю 4 операции , каждая из которых зависит от последней , для проверки и выполнения следующих шагов.Более конкретно, каждый раз, когда пользователь хочет сделать снимок и загрузить его, я запрашиваю доступ к камере и доступ к местоположению.

Операции:
1. RequestCameraAccessOperation
2. RequestLocationWhenInUseOperation
3. TakePictureOperation
4. GetLocationOperation

Цепочка зависимостей:
2 зависит от 1
3 зависит от 2
4 зависит от 3

Я сейчас добавляю в проверку ошибоки отмена операции и зависимых операций.Сейчас я тестирую отмену, добавляя вызов cancel () в конце первой операции в main ().Однако ни одна из зависимых операций не отменяется.Я проверяю их основные методы, чтобы увидеть, отменены ли они, но, похоже, это ничего не делает.Документация гласит:

Как только вы добавляете операцию в очередь, операция уже не в ваших руках.Очередь вступает во владение и обрабатывает планирование этой задачи.Однако, если позже вы решите, что не хотите выполнять операцию в конце концов - поскольку пользователь нажал кнопку отмены на панели прогресса или, например, закрыли приложение - вы можете отменить операцию, чтобы предотвратить ненужное использование процессорного времени,Это можно сделать, вызвав метод cancel () самого объекта операции или вызвав метод cancelAllOperations () класса OperationQueue.Отмена операции не заставляет ее немедленно прекратить то, что она делает.Хотя соблюдение значения в свойстве isCancelled ожидается для всех операций, ваш код должен явно проверить значение в этом свойстве и при необходимости прервать его.

Вот код для моих операций:

Создание операций и установка зависимостей

    // create operations
    let requestCameraAccessOp = RequestCameraAccessOperation()
    let requestLocationWhenInUseOp = RequestLocationWhenInUseOperation()
    let takePictureOp = TakePictureOperation(viewController: self)
    let locationOp = GetLocationOperation(locationManager: locationManager)

    locationOp.completionBlock = { [weak networkManager, unowned self] in
      // code that unwraps optionals and sends them to the networkManager
      self.dismiss(animated: true, completion: nil)
    }

    // set operation dependencies
    requestLocationWhenInUseOp.addDependency(requestCameraAccessOp)
    takePictureOp.addDependency(requestLocationWhenInUseOp)
    locationOp.addDependency(takePictureOp)

    // add operations to the queue
    operationQueue.addOperations([requestCameraAccessOp,
                                  requestLocationWhenInUseOp,
                                  takePictureOp,
                                  locationOp],
                                 waitUntilFinished: false)

1-я операция

class RequestCameraAccessOperation: Operation {
  let imagePicker = UIImagePickerController()
  var error: AVError.Code?

  override func main() {
    if isCancelled { return }

    let available = UIImagePickerController.isSourceTypeAvailable(.camera)
    let status = AVCaptureDevice.authorizationStatus(for: .video)

    switch (available, status) {
    case (false, _):
      error = AVError.contentIsUnavailable
    case (true, .authorized):
      break
    case (true, .notDetermined):
      AVCaptureDevice.requestAccess(for: .video) { accessGranted in
        if !accessGranted {
          self.error = AVError.applicationIsNotAuthorizedToUseDevice
        }
      }
    case (true, .restricted):
      fallthrough
    case (true, .denied):
      // present alert to the user to change authorization in settings
    case (true, _):
      error = AVError.unknown
    }

    // always cancel for now to test that cancellation works
    self.cancel()

//    if let error = error {
//      self.cancel()
//    }
  }
}

2-я операция

class RequestLocationWhenInUseOperation: Operation {
  var error: OperationError?

  override func main() {
    if isCancelled {
      cancel()
    }

    let enabled = CLLocationManager.locationServicesEnabled()
    let status = CLLocationManager.authorizationStatus()

    switch (enabled, status) {
    case (true, .authorizedWhenInUse):
      break
    case (true, .authorizedAlways):
      break
    default:
      // unsure of how to handle errors
      error = .failed("Error")
    }

//    if let error = error {
//      completion(.failed)
//    } else {
//      completion(.satisfied)
//    }
  }
}

3-я и 4-я операции имеют одинаковые проверки отмены, поэтому я буду избегать избыточности и пропущу публикацию их кода.

Из того, что я могу понять, есть3 варианта того, почему отмена не работает.

  1. Это не работает так, как мне кажется.Вызов отмены в 1-й операции не помечает зависимые операции как отмененные, поэтому проверка отмены в зависимых операциях никогда не оценивается как true.

Редактировать: После прочтения это , кажется, что мое предположение неверно, пометка операции не отменяет зависимые операции.

Чтобы добиться этого, лучше разделить их, используя очередь на группу.Поэтому для каждой группы создайте подкласс NSOperation в параллельном режиме, включите очередь, добавьте каждую подоперацию в очередь.Отмените отмену и вызовите [супер отмену], затем [self.queue cancelAllOperations].

Мне нужно вызвать cancelAllOperations для самой операцииQueue.Я не знаю, как я проверил бы отмену и вызывал бы это между операциями.У меня нет контроля над операцией Queue после добавления операций.Это, вероятно, выполнимо, но это кажется слишком сложным, а не то, что было бы «умным» решением.

Что этот блог сообщение описывает, где начинаются зависимые операциивыполнение сразу после того, как предыдущая операция помечена как завершенная.

Что я не вижу?

...