【问题标题】:iOS swift Operation QueueiOS swift操作队列
【发布时间】:2023-03-18 22:35:01
【问题描述】:

我正在开发使用 OperationQueue 的 iOS 应用程序。我创建了 2 个操作。 Operation2 依赖于 Operation1 的完成。Operation2 如果正在运行,则需要等到 Operation 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

我在这里有什么遗漏吗?

【问题讨论】:

  • 不确定我是否理解您的问题。您在问题的第 2 行中写到 operation2 可以在 operation1 正在进行或完成后开始。这是一个错字吗,因为如果您添加依赖项,它将等到 operation1 完成。为什么在将codeToRun 添加到队列后设置它。需要在将其添加到队列之前完成。
  • 你的操作的这个实现是从某个地方复制过来的吗?您的代码存在许多问题。能否请您阅读操作文档。
  • codeToRun 在添加到队列之前设置。已更正。
  • 您希望在第一次操作完成后开始第二次操作吗?如果是这样,您可以编辑问题的第二行吗?
  • 更正谢谢

标签: swift concurrency nsoperationqueue nsoperation operation


【解决方案1】:

我一直在查看您的代码。我发现了一些东西:

首先

manager.doOperation1()
manager.doOperation2()

这并不意味着 operation2 在 operation1 完成后运行,如果你想这样做,你可以为 operation1 添加一个完成闭包。

第二

当你打电话时

doOperation2()

在这个函数中似乎代码从未执行过:

guard let operation2 = self.operation2 else { return }

毕竟

您似乎想创建自己的轮子。我建议你学习一些关于 GCD 的知识,你可以在这里找到资源:

Grand Central Dispatch Crash Course for Swift 3

Grand Central Dispatch Tutorial for Swift 3: Part 1/2

【讨论】:

  • 感谢您的文档。我想使用 OperationQueue 而不是 GCD。我试图弄清楚为什么依赖不起作用
【解决方案2】:

有几件事:

实施:

  • isExecutingisFinished 实现KVO
  • 修复doOperation2
  • 一旦您设置了依赖关系,即使 operation2 被添加到队列中,它也不会启动,直到 operation1 完成。
  • 检查 MyOperation 内的 isCancelled

下面不是实现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() 是另一个操作。
  • 所以一个操作包含业务逻辑。
  • 您可以在调用站点添加依赖项。

【讨论】:

    【解决方案3】:

    您需要做的只是添加对依赖操作的依赖。

    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)
    

    希望这可以帮助您解决依赖问题。

    【讨论】:

      猜你喜欢
      • 2011-10-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多