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
I wanted to have cancellable blocks that my UICollectionViewController could easily cancel once cells were scrolled off the screen. The blocks are not doing network ops, they are doing image operations (resizing, cropping etc). The blocks themselves need to have a reference to check if their op has been cancelled, and none of the other answers (at the time I wrote this) provided that.
Here's what worked for me (Swift 3) - making blocks that take a weak ref to the BlockOperation, then wrapping them in the BlockOperation block itself:
public extension OperationQueue {
func addCancellableBlock(_ block: @escaping (BlockOperation?)->Void) -> BlockOperation {
let op = BlockOperation.init()
weak var opWeak = op
op.addExecutionBlock {
block(opWeak)
}
self.addOperation(op)
return op
}
}
Using it in my UICollectionViewController:
var ops = [IndexPath:Weak]()
func collectionView(_ collectionView: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath) {
...
ops[indexPath] = Weak(value: DispatchQueues.concurrentQueue.addCancellableBlock({ (op) in
cell.setup(obj: photoObj, cellsize: cellsize)
}))
}
func collectionView(_ collectionView: UICollectionView, didEndDisplaying cell: UICollectionViewCell, forItemAt indexPath: IndexPath) {
if let weakOp = ops[indexPath], let op: BlockOperation = weakOp.value {
NSLog("GCV: CANCELLING OP FOR INDEXPATH \(indexPath)")
op.cancel()
}
}
Completing the picture:
class Weak {
weak var value : T?
init (value: T) {
self.value = value
}
}