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

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了理解Swift中具有依赖性的操作序列相关的知识,希望对你有一定的参考价值。

引用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
答案

事实上,我无法确定为什么你的代码不能正常工作的神秘之处,但我想出了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。

希望这有帮助。

另一答案

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

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

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

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

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

另一答案

您需要将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)
另一答案

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

另一答案

初始化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
另一答案

我测试使用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)
另一答案

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

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)

以上是关于理解Swift中具有依赖性的操作序列的主要内容,如果未能解决你的问题,请参考以下文章

时间序列数据之一二三阶指数平滑法(Python代码)

Swift 命令行程序中的 CFRunLoop

具有Swift 4依赖项的Swift 3 Cocoapod

如何将这个 Objective-C 代码片段写入 Swift?

swift常用代码片段

如何使用 Swift 使用此代码片段为 iOS 应用程序初始化 SDK?