NSOperation has not deallocated

Viewed 79

I have

class BoxSizeViewDetailController: UIViewController {

    weak var output: BoxSizeViewDetailControllerOutput?

    @objc
    private func save() {

        SLPWait.show()

        Thread.run {
            let operation = MoveBoxWithSizeToAssemblyOperation(boxBarcode: self.boxBarcode, assemblyRef: self.assemblyRef, boxSize: self.boxSize)
            operation.completion = { [weak self] error in

                Thread.main {
                    SLPWait.hide()

                    if let error = error {
                        error.alert()
                        return
                    }

                    self?.output?.didSaved()
                    self?.pop()
                }
            }

            let operationQueue = OperationQueue()
            operationQueue.addOperations(operation, waitUntilFinished: true)
        }
    }
}

And

class MoveBoxWithSizeToAssemblyOperation: SLPAsyncOperation {

    private let boxBarcode: String
    private let assemblyRef: String
    private let boxSize: BoxSize

    var withSize: Bool = false

    var completion: ((NSError?) -> Void)?

    init(boxBarcode: String, assemblyRef: String, boxSize: BoxSize) {
        self.boxBarcode = boxBarcode
        self.assemblyRef = assemblyRef
        self.boxSize = boxSize
    }

    deinit {
        SLPLog.debug("Deinit", String(describing: self))
    }

    override func start() {
        if isCancelled {
            self.finish()
            return
        }
        super.start()
    }


    override func main() {
        defer {
            self.finish()
        }

        let sendSizeOperation = SendSizeOperation(barcode: boxBarcode, boxSize: boxSize)
        let moveBoxToAssemblyOperation = MoveBoxToAssemblyOperation(boxBarcode: boxBarcode, assemblyRef: assemblyRef)

        sendSizeOperation.completion = { [unowned moveBoxToAssemblyOperation, weak self] error in
            //Here is main thread
            if let error = error {
                moveBoxToAssemblyOperation.cancel()
                self?.completion?(error)
            }

        }

        moveBoxToAssemblyOperation.completion = { [weak self] error in
            //Here is main thread
            self?.completion?(error)
        }

        moveBoxToAssemblyOperation.addDependency(sendSizeOperation)

        let operationQueue = OperationQueue()
        operationQueue.qualityOfService = .userInitiated
        operationQueue.addOperations([sendSizeOperation, moveBoxToAssemblyOperation], waitUntilFinished: true)

    }

}

And

public extension Thread {
    class func run(execute: @escaping @convention(block) () -> Void) {
        DispatchQueue.global(qos: .userInitiated).async(execute: execute)
    }

    class func run(execute: DispatchWorkItem) {
        DispatchQueue.global(qos: .userInitiated).async(execute: execute)
    }

    class func main(execute: @escaping @convention(block) () -> Void) {
        DispatchQueue.main.async(execute: execute)
    }

    class func main(execute: DispatchWorkItem) {
        DispatchQueue.main.async(execute: execute)
    }
}

So the problem is in this part of code

Thread.run {

    let operation = MoveBoxWithSizeToAssemblyOperation(boxBarcode: self.boxBarcode, assemblyRef: self.assemblyRef, boxSize: self.boxSize)
    operation.completion = { [weak self] error in

        Thread.main {
            SLPWait.hide()

            if let error = error {
                error.alert()
                return
            }

            self?.output?.didSaved()
            self?.pop()
        }
    }

    let operationQueue = OperationQueue()
    operationQueue.addOperations(operation, waitUntilFinished: true)
}

SLPWait.show() and SLPWait.hide() just show and hide an ActivityIndicator.

The operations MoveBoxWithSizeToAssemblyOperation is not dealloceted (sometimes) and sometimes is dealloceted. Why is that?

My way of thinking. Because I use Thread.run to dispatch from main queue, I think I need wait until "MoveBoxWithSizeToAssemblyOperation" completes and handle completion. But "MoveBoxWithSizeToAssemblyOperation" completes and handle "defer { self.finish }" but not deallocated.

My misunderstanding questions:

  1. I don't understand should I set waitUntilFinished" = true ? Because I block thread.run and not the main thread though MoveBoxToAssemblyOperation completes on main thread. Is the MoveBoxToAssemblyOperation block main thread when completes ?
  2. When I write Thread.run { should I capture [weak self] or not ?
  3. Why MoveBoxWithSizeToAssemblyOperation is not deallocated ?
0 Answers
Related