Reputation: 143
I am working on iOS app where I am using OperationQueue. I have created 2 operations. Operation2 is dependent on completion of Operation1.Operation2 needs to wait until Operation 1 get finished if its running. If operation 1 is not running then operation 2 should start immediately.
Its not working as expected so I am testing in playground
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()
I am getting result
cancelAllOperations
setup Called
operation1 started
operation1 completed
operation1.completionBlock
Expected is
cancelAllOperations
setup Called
operation1 started
operation1 completed
operation1.completionBlock
operation2 started
operation2 completed
Am I missing here anything?
Upvotes: 2
Views: 6738
Reputation: 4120
All you need to do is just add dependency on the dependent operation.
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)
Hope this may help you solve your dependency problem.
Upvotes: 0
Reputation: 21
I've been looking at your code. I found a few things:
manager.doOperation1()
manager.doOperation2()
this not means operation2 runs after operation1 finished, if you want to do this, you can add a completion closure for operation1.
when you call
doOperation2()
in this function seems like the code never executed after:
guard let operation2 = self.operation2 else { return }
It seems like you want to create your own wheels. I suggest you to learn something about GCD,you can find resources here:
Grand Central Dispatch Crash Course for Swift 3
Grand Central Dispatch Tutorial for Swift 3: Part 1/2
Upvotes: 1
Reputation: 17685
There are a couple of things:
KVO
for isExecuting
and isFinished
doOperation2
operation2
wouldn't start even if it is added to the queue until operation1
completes.MyOperation
Below is not the ideal way to implement doOperation2
, but removes some of the clutter from your code. I will leave it to you to implement the whole thing based on the Design section mentioned below.
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
seems to be generic and you seem to be doing most of the real work at the place where you call themMyOperation
to do the real work.FetchData()
is an operation, ParseData()
is another operation. Upvotes: 0