Очередь быстрой операции iOS

Я работаю над приложением iOS, где использую OperationQueue. Я создал 2 операции. Операция 2 зависит от завершения операции 1. Операция 2 должна дождаться завершения операции 1, если она выполняется. Если операция 1 не выполняется, то операция 2 должна начаться немедленно.

Он не работает должным образом, поэтому я тестирую его на игровой площадке.

    class MyManager {

        var operationQueue: OperationQueue?

        var operation1: MyOperation? = nil
        var operation2: MyOperation? = nil

        typealias completion = (_ serverError: String?) -> Void

        func talkWithServer(completion: completion?) {

            completion?("competed!")
        }

        func doOperation1() {

            cancelProcess()
            setup()

            guard let operation1 = self.operation1 else { return }
            operation1.codeToRun = {
                print("operation1 started")
                self.talkWithServer(completion: { (completion) in
                    print("operation1 completed")
                    operation1.markAsFinished()
                })
            }
            operationQueue?.addOperation(operation1)

        }


        func doOperation2() {
           self.operation2 = MyOperation()

            guard let operation2 = self.operation2 else { return }



            operation2.codeToRun = {
                print("operation2 started")
                self.talkWithServer(completion: { (completion) in
                    print("operation2 completed")
                    operation2.markAsFinished()
                })
            }

if let operation1 = self.operation1 {
            if operation1.isExecuting {
                operation2.addDependency(operation1)
                operation1.completionBlock = {
                    print("operation1.completionBlock")
                    self.operationQueue?.addOperation(operation2)
                }
            }
            } else  {
                operationQueue?.addOperation(operation2)
            }

        }


        func cancelProcess() {
            print("cancelAllOperations")
            operationQueue?.cancelAllOperations()
        }

        func setup() {
            print("setup Called")
            operationQueue?.cancelAllOperations()
            operationQueue = OperationQueue()
            operation1 = MyOperation()
            operation2 = MyOperation()
        }
    }


    class MyOperation: Operation {
        var codeToRun: (()->Void)?

        var _executing = false
        var _finished = false

        override internal(set) var isExecuting: Bool {
            get {
                return _executing
            }
            set {
                _executing = newValue

            }
        }

        override internal(set) var isFinished: Bool {
            get {
                return _finished
            }
            set {
                _finished = newValue
            }
        }

        override var isAsynchronous: Bool {
            return true
        }

        override func start() {
            isExecuting = true
            isFinished = false
            if let closure = self.codeToRun {
                closure()
            }
        }

        func markAsFinished() {
            self.isExecuting = false
            self.isFinished = true
            completionBlock?()
        }
    }

    let manager = MyManager()

    manager.doOperation1()
    manager.doOperation2()

я получаю результат

cancelAllOperations
setup Called
operation1 started
operation1 completed
operation1.completionBlock

Ожидается

cancelAllOperations
setup Called
operation1 started
operation1 completed
operation1.completionBlock
operation2 started
operation2 completed

Я что-то пропустил здесь?


person Kapil    schedule 03.02.2018    source источник
comment
Не уверен, что понимаю ваш вопрос. Вы написали во 2-й строке своего вопроса, что операция 2 может начаться после того, как операция 1 выполняется или завершается. Это опечатка, потому что если вы добавите зависимость, она будет ждать завершения операции 1. Почему вы устанавливаете codeToRun после добавления в очередь. Это необходимо сделать перед добавлением в очередь.   -  person user1046037    schedule 03.02.2018
comment
Эта реализация вашей операции скопирована откуда-то? Есть ряд проблем с вашим кодом. Не могли бы вы прочитать документацию Operation.   -  person user1046037    schedule 03.02.2018
comment
codeToRun устанавливается перед добавлением в очередь. Исправлено.   -  person Kapil    schedule 03.02.2018
comment
Вы хотите, чтобы 2-я операция запускалась после завершения 1-й операции? Если да, не могли бы вы отредактировать вторую строку своего вопроса?   -  person user1046037    schedule 03.02.2018
comment
Исправлено Спасибо   -  person Kapil    schedule 03.02.2018
comment
Два способа добиться этого — добавить операцию1 в качестве зависимости от операции2, но, конечно же, у вас никогда не будет операции1 по какой-то причине, которая не работает. Другой способ — установить для свойства maxConcurrentOperationCount очереди операций значение 1, чтобы в любой момент времени могла выполняться только 1 операция. Затем, если операция 1 начинается первой, операция 2 должна ждать ее, но если операции 1 нет, операция 2 просто начнется. При этом операции будут выполняться в том порядке, в котором они были добавлены, и каждая из них ожидает завершения предыдущей.   -  person Upholder Of Truth    schedule 03.02.2018


Ответы (3)


Я смотрел на ваш код. Я нашел несколько вещей:

Первый

manager.doOperation1()
manager.doOperation2()

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

Второй

когда ты звонишь

doOperation2()

в этой функции кажется, что код никогда не выполнялся после:

guard let operation2 = self.operation2 else { return }

После всего

Похоже, вы хотите создать свои собственные колеса. Я предлагаю вам узнать кое-что о GCD, вы можете найти ресурсы здесь:

Ускоренный курс Grand Central Dispatch для Swift 3

Учебное пособие по Grand Central Dispatch для Swift 3: Часть 1 /2

person Leacode Lea    schedule 03.02.2018
comment
Спасибо за документацию. Я хотел бы использовать OperationQueue вместо GCD. Я пытаюсь понять, почему зависимость не работает - person Kapil; 03.02.2018

Есть пара вещей:

Реализация:

  • Реализовать KVO для isExecuting и isFinished
  • Исправить doOperation2
  • После того, как вы установите зависимости, operation2 не запустится, даже если он будет добавлен в очередь, пока operation1 не завершится.
  • Проверьте isCancelled внутри MyOperation

Ниже приведен не идеальный способ реализации doOperation2, но он удаляет часть беспорядка из вашего кода. Я оставлю вам возможность реализовать все это на основе раздела «Дизайн», упомянутого ниже.

func doOperation2() {

    self.operation2 = MyOperation()

    guard let operation2 = self.operation2 else {
        return
    }

    operation2.codeToRun = {
        print("operation2 started")

        self.talkWithServer(completion: { (completion) in
            print("operation2 completed")
        })
    }

    operationQueue?.addOperation(operation2)
}

Дизайн:

  • В вашей реализации MyOperation кажется общим, и вы, похоже, выполняете большую часть реальной работы в том месте, где вы их вызываете.
  • Измените MyOperation, чтобы выполнить настоящую работу.
  • Сайт вызова должен быть простым
  • Пример FetchData() — операция, ParseData() — другая операция.
  • Таким образом, операция содержит бизнес-логику.
  • На сайте вызова вы можете просто добавить зависимости.
person user1046037    schedule 03.02.2018

Все, что вам нужно сделать, это просто добавить зависимость от зависимой операции.

let queue = OperationQueue()

let operation1 = BlockOperation(block: { [weak self] in
    self?.doOperation1()
})

let operation2 = BlockOperation(block: { [weak self] in
    self?.doOperation2()
})

operation1.addDependency(operation2) // THIS IS THE KEY CODE IN YOUR CASE

queue.addOperation(operation1)
queue.addOperation(operation2)

Надеюсь, это поможет вам решить проблему зависимости.

person Dhaval H. Nena    schedule 25.06.2018