I have a long running loop I want to run in the background with an NSOperation
. I\'d like to use a block:
NSBlockOperation *operation = [NSBlock
With Swift 5, you can create a cancellable BlockOperation
with addExecutionBlock(_:). addExecutionBlock(_:)
has the following declaration:
func addExecutionBlock(_ block: @escaping () -> Void)
Adds the specified block to the receiver’s list of blocks to perform.
The example below shows how to implement addExecutionBlock(_:)
:
let blockOperation = BlockOperation()
blockOperation.addExecutionBlock({ [unowned blockOperation] in
for i in 0 ..< 10000 {
if blockOperation.isCancelled {
print("Cancelled")
return // or break
}
print(i)
}
})
Note that, in order to prevent a retain cycle between the BlockOperation
instance and its execution block, you have to use a capture list with a weak
or unowned
reference to blockOperation
inside the execution block.
The following Playground code shows how to cancel a BlockOperation
subclass instance and check that there is no retain cycle between it and its execution block:
import Foundation
import PlaygroundSupport
PlaygroundPage.current.needsIndefiniteExecution = true
class TestBlockOperation: BlockOperation {
deinit {
print("No retain cycle")
}
}
do {
let queue = OperationQueue()
let blockOperation = TestBlockOperation()
blockOperation.addExecutionBlock({ [unowned blockOperation] in
for i in 0 ..< 10000 {
if blockOperation.isCancelled {
print("Cancelled")
return // or break
}
print(i)
}
})
queue.addOperation(blockOperation)
Thread.sleep(forTimeInterval: 0.5)
blockOperation.cancel()
}
This prints:
0
1
2
3
...
Cancelled
No retain cycle