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

问题描述 投票:6回答:8

引用https://developer.apple.com/reference/foundation/operation,我将游乐场设置为 -

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
ios swift nsoperation nsoperationqueue
8个回答
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。

希望这有帮助。


2
投票

根据完成块的文件(强调我的),

您的完成块的确切执行上下文无法保证,但通常是辅助线程。因此,您不应该使用此块来执行任何需要非常特定的执行上下文的工作。 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
投票

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

正如在@ 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

第一个操作在启动其依赖项之前结束,但在依赖项已经启动之后调用完成块。


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)

0
投票

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


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

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)

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)
© www.soinside.com 2019 - 2024. All rights reserved.