I'm learning OperationQueue
. What I want to do is to prevent network calls if there's an ongoing call. The problem is that when I tap on the button, a new operation is being added to the queue.
class ViewController: UIViewController {
private var queue = OperationQueue()
func networkCall(completion: (()->Void)?) {
DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(3)) {
completion?()
}
}
lazy var button: UIButton = {
let b = UIButton(type: .custom)
b.backgroundColor = .black
b.setTitleColor(.white, for: .normal)
b.setTitle("CLICK!~", for: .normal)
b.addTarget(self, action: #selector(self.boom), for: .touchUpInside)
return b
}()
@objc func boom() {
print("BOOM!")
self.queue.maxConcurrentOperationCount = 1
let block = BlockOperation()
block.addExecutionBlock {
self.networkCall {
print("DONE NETWORK CALL!")
}
}
self.queue.addOperation(block)
DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(1)) {
self.queue.cancelAllOperations()
}
}
override func viewDidLoad() {
super.viewDidLoad()
self.view.backgroundColor = .gray
self.view.addSubview(self.button)
self.button.translatesAutoresizingMaskIntoConstraints = false
self.button.centerYAnchor.constraint(equalTo: self.view.centerYAnchor).isActive = true
self.button.centerXAnchor.constraint(equalTo: self.view.centerXAnchor).isActive = true
self.button.widthAnchor.constraint(equalToConstant: 100.0).isActive = true
self.button.heightAnchor.constraint(equalToConstant: 50.0).isActive = true
}
}
Am I missing something?
Unfortunately, you can’t just add an asynchronous method to a BlockOperation
. The operation, itself, is going to complete as soon as the asynchronous network request is submitted (even though you’ve deferred the completion?()
an arbitrary 3 seconds later).
Instead, you’re going to want to wrap the network request in a custom, asynchronous, Operation
subclass method that does all the KVO notifications for proper Operation
behaviors. See the Operation
documentation for details.
See https://stackoverflow.com/a/32322851/1271826 for example with downloadTask
implementation. Or see https://stackoverflow.com/a/48104095/1271826 for general discussion.
By the way, even though you won’t be using BlockOperation
, in those cases where you do, be mindful of the addExecutionBlock
of BlockOperation
. You can, for example, have a serial queue, create a BlockOperation
, and then add multiple addExecutionBlock
for a given operation, and they will not be serial. Individual operations will behave serially, but not individual blocks you add to a given BlockOperation
. I’d generally advise people to avoid addExecutionBlock
with BlockOperation
until you really grok what’s going on there. Better to just use the main closure when you initialize BlockOperation
.