1
\$\begingroup\$

Here is a very handy subclass of Operation that allows to do asynchronous tasks inside an OperationQueue:

public class ManuallyCompletableOperation: Operation {
    var debugLabel: String?

    // Override read-only superclass property as read-write.
    private(set) override public var isExecuting: Bool {
        get { return _isExecuting }
        set {
            willChangeValue(forKey: "isExecuting")
            _isExecuting = newValue
            didChangeValue(forKey: "isExecuting")
        }
    }

    // Override read-only superclass property as read-write.
    private(set) override public var isFinished: Bool {
        get { return _isFinished }
        set {
            willChangeValue(forKey: "isFinished")
            _isFinished = newValue
            didChangeValue(forKey: "isFinished")
        }
    }

    private var _isFinished = false
    private var _isExecuting = false

    /**
     - Important: Never put strong reference to the operation inside the block.
     */
    var block: (()->())?

    override public func start() {
        if isCancelled {
            isFinished = true
            return
        }

        isExecuting = true

        if let existingBlock = block {
            existingBlock()
        } else {
            complete()
        }
    }

    public override func cancel() {
        block = nil
        super.cancel()
    }

    /**
     This must be called somewhere inside the block 
     in order to complete the operation.
     */
    func complete() {
        block = nil
        isExecuting = false
        isFinished = true
    }
}

Usage:

let op = ManuallyCompletableOperation()
op.block = { [weak op] in
    // ...
    doAsyncStuffWithCompletion({
        // ...
        op?.complete()
    })
}

I understand that this class is vulnerable.

1) If complete() isn't called the entire queue will get stuck.

2) Putting strong reference to the operation inside the block will lead to retain cycle.

How can I improve ManuallyCompletableOperation design to reduce risks of wrong usage? May be there are exist some patterns or best practices applicable to this case?

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.