理解Swift中具有依赖性的操作序列

时间:2017-02-14 09:50:35

标签: ios swift nsoperation nsoperationqueue

参考https://developer.apple.com/reference/foundation/operation,我将Playground设置为 -

class myOperation1 : Operation {
    override func main() {
        print("op1 working....")
    }
}

class myOperation2 : Operation {
    override func main() {
        print("op2 working....")
    }
}

let op1 = myOperation1()
let op2 = myOperation2()

op1.completionBlock = {
    print("op1 finished")
}

op2.completionBlock = {
    print("op2 finished")
}

op2.addDependency(op1)

let opsQue = OperationQueue()
opsQue.addOperation(op1)
opsQue.addOperation(op2)

控制台日志是 -

op1 working....
op2 working....
op1 finished
op2 finished

我们不应该期望输出是依赖的结果吗? -

op1 working....
op1 finished
op2 working....
op2 finished

使用 - opsQue.addOperations([op1, op2], waitUntilFinished: true)

的结果相同
op1 working....
op2 working....
op1 finished
op2 finished

8 个答案:

答案 0 :(得分:3)

事实上,我无法确定为什么你的代码不能正常工作的原因是什么,但我想出了3个解决方法来实现你想要的东西:

如果您希望输出始终

op1 working....
op1 finished
op2 working....
op2 finished

然后:

1 - 您可能希望将第二个操作添加到第一个操作的完成块中的队列中,如下所示:

class myOperation1 : Operation {
    override func main() {
        print("op1 working....")
    }
}

class myOperation2 : Operation {
    override func main() {
        print("op2 working....")
    }
}

let opsQue = OperationQueue()

let op1 = myOperation1()

op1.completionBlock = {
    print("op1 finished")

    opsQue.addOperation(op2)
}

let op2 = myOperation2()

op2.completionBlock = {
    print("op2 finished")
}

opsQue.addOperation(op1)

2 - maxConcurrentOperationCount操作队列设置为1,如下所示:

class myOperation1 : Operation {
    override func main() {
        print("op1 working....")
    }
}

class myOperation2 : Operation {
    override func main() {
        print("op2 working....")
    }
}

let op1 = myOperation1()
let op2 = myOperation2()

op1.completionBlock = {
    print("op1 finished")
}

op2.completionBlock = {
    print("op2 finished")
}

op2.addDependency(op1)

let opsQue = OperationQueue()
// setting maxConcurrentOperationCount to 1
opsQue.maxConcurrentOperationCount = 1
opsQue.addOperation(op1)
opsQue.addOperation(op2)

3 - 在将第一个操作添加到队列后调用waitUntilAllOperationsAreFinished(),如下所示:

let opsQue = OperationQueue()
opsQue.addOperation(op1)
opsQue.waitUntilAllOperationsAreFinished()
opsQue.addOperation(op2)
不过,对于非复杂的任务,我更喜欢使用GCD。

希望这会有所帮助。

答案 1 :(得分:1)

根据完成模块(重点是我的)的文档,

  

不能保证用于完成块的确切执行上下文,但通常是辅助线程。因此,您不应使用此块来执行需要非常特定的执行上下文的任何工作。   https://developer.apple.com/documentation/foundation/operation/1408085-completionblock

因此,从更现实的意义上来说,当您想确切地知道某个操作何时完成时,您会执行以下操作:

class myOperation1 : Operation {
    override func main() {
        print("op1 working....")
        //Do things
        print("op1 finished")
    }
}

class myOperation2 : Operation {
    override func main() {
        print("op2 working....")
        //Do things
        print("op2 finished")
    }
}

答案 2 :(得分:1)

在依赖操作开始后调用完成块,但这并不意味着第一个操作没有结束。

如@Xoronis的答案中所述:

  

不能保证您的完成块的确切执行上下文,但通常是辅助线程。因此,您不应使用此块来执行需要非常特定的执行上下文的任何工作。

https://developer.apple.com/documentation/foundation/operation/1408085-completionblock

看看这个例子:

class myOperation1 : Operation {
    override func main() {
        print("op1 working....")
        for i in 1...10 {
            print("\(i)")
        }
    }
}

class myOperation2 : Operation {
    override func main() {
        print("op2 working....")
    }
}

let op1 = myOperation1()
let op2 = myOperation2()

op1.completionBlock = {
    print("op1 completed")
}

op2.completionBlock = {
    print("op2 completed")
}

op2.addDependency(op1)

let opsQue = OperationQueue()
opsQue.addOperations([op1, op2], waitUntilFinished: true)

将导致

op1 working....
1
2
3
4
5
6
7
8
9
10
op2 working....
op1 completed
op2 completed

第一个操作确实在开始依赖之前结束,但是在依赖已经开始之后调用完成块。

答案 3 :(得分:1)

您需要将操作队列的maxConcurrentOperationCount设置为1,这样才能正常工作。

     let operationQueue = OperationQueue()
     operationqueue?.maxConcurrentOperationCount = 1

    let operation1 = Operation()
    let operation2 = Operation()

    operation1.completionBlock = {
        print("operation1 finished")
    }

    operation2.completionBlock = {
        print("operation2 finished")
    }

    operation2.addDependency(operation1)

    operationQueue.addOperation(operation1)
    operationQueue.addOperation(operation2)

答案 4 :(得分:0)

通过指定依赖关系,可以保证op2op1完成后进行调度,但不一定op2op1的完成处理程序完成后进行调度

答案 5 :(得分:0)

初始化operationQueue暂停将为您提供所需内容。

let queue = OperationQueue()
let downloadOp = Operation()
let resizeOp = Operation()
downloadOp.dependency(resizeOp)
queue.isSuspended = true
queue.addOperation(downloadOp)
queue.addOperation(resizeOp)
queue.isSuspended = false

答案 6 :(得分:0)

我测试过使用isSuspended。每次操作完成后,即可操作主队列。

class OperationChain: Operation {
    var mainQ: OperationQueue?
    var text: String?
    
    init(with name: String, by mainqueue:OperationQueue){
        self.text = name
        self.mainQ = mainqueue
    }
    
    override func main() {
        self.mainQ!.isSuspended = true
        print(text!)
        sleep(5)
        self.mainQ!.isSuspended = false
    }
}

let oq = OperationQueue()
oq.maxConcurrentOperationCount = 1

let q1 = OperationChain(with: "Operation.main.q1", by: oq)
print("q1")

q1.completionBlock = {
    //sleep(5)
    q1.mainQ!.isSuspended = true
    var i = 0
    repeat {
        i = i + 1
    } while i < 100
    print("q1.completionBlock") 
    q1.mainQ!.isSuspended = false
}

oq.addOperations([q1], waitUntilFinished: true)

答案 7 :(得分:0)

您可以使用适配器来确保执行顺序:

op1 working....
op1 finished
op2 working....
op2 finished

这是修改后的代码:

import Foundation

class myOperation1 : Operation {
    override func main() {
        print("op1 working....")
    }
}

class myOperation2 : Operation {
    override func main() {
        print("op2 working....")
    }
}

let op1 = myOperation1()
let op2 = myOperation2()

op1.completionBlock = {
    print("op1 finished")
}

op2.completionBlock = {
    print("op2 finished")
}

let adapter = BlockOperation(block: {})

adapter.addDependency(op1)
op2.addDependency(adapter)

let opsQue = OperationQueue()
opsQue.addOperation(op1)
opsQue.addOperation(op2)
opsQue.addOperation(adapter)