【问题标题】:How to check if operation was cancelled?如何检查操作是否被取消?
【发布时间】:2019-11-27 13:45:32
【问题描述】:

我想知道我的操作是否被取消或正常完成。这是我的代码 sn-p :

class PacketReceiver {
    private let m_executer = OperationQueue()
    private var m_operation : Operation?

    private func operationFinishedHandler()
    {
        if let op = m_operation {
            if op.isCancelled {
                print("Operation cancelled")
            } else {
                print("Operation finished OK \(op.isCancelled)")
            }
        }
    }

    func start()
    {
        let rxPacketOperation = PacketReceiverOperation()
        rxPacketOperation.completionBlock = self.operationFinishedHandler
        m_operation = rxPacketOperation

        m_executer.addOperation(rxPacketOperation)
    }

    func cancel()
    {
        if let op = m_operation {
            op.cancel()
        }
    }

    func join()
    {
        if let op = m_operation {
            print("is op cancelled = \(op.isCancelled)")
        }

        m_executer.waitUntilAllOperationsAreFinished()

        if let op = m_operation {
            print("is op cancelled = \(op.isCancelled)")
        }
    }
}

后来我有:

let packetReceiver = PacketReceiver()
packetReceiver.start()

packetReceiver.cancel()
packetReceiver.join()

我看到join() 方法内部isCancelled 属性设置为true。但是当我在完成的处理程序中检查它时,它是错误的。我想这是一种预期的行为。但是检查我的操作是否被取消的正确方法是什么?

这是我的操作课:

class PacketReceiverOperation : Operation {
    private var m_packetData : String = ""
    private let m_simDataProvider = SimDataProvider(okAttemptId : 2)
    private let m_currentTimeProvider = CurrentTimeProvider()

    private func prepareReceiver() {
        m_packetData = ""
        print("\(m_currentTimeProvider.getCurrentTimeAsString()) : prepare SIM receiver")
    }

    override func main() {
        if isCancelled {
            return
        }

        prepareReceiver()

        if isCancelled {
            return
        }

        var isPacketReceived = false
        var isFirstChunkReceived = false

        repeat {
            if isCancelled {
                return
            }

            if let chunkData = m_simDataProvider.getPacket() {
                isFirstChunkReceived = true
                m_packetData.append(";" + chunkData)
            } else {
                if isFirstChunkReceived {
                    isPacketReceived = true
                }
            }
        } while isPacketReceived == false
    }
}

【问题讨论】:

    标签: swift nsoperationqueue nsoperation


    【解决方案1】:

    由于各种原因(特别是缺乏抢先取消和一般竞争条件),isCancelled 状态不是了解您的 Operation 子类是否成功完成的可靠方法,无论如何。 (它告诉您是否尝试取消,但不告诉您底层任务是否成功。)

    出于这个原因,我很少使用内置的completionHandler(没有参数),而是通常实现我自己的自定义完成处理程序闭包,它提供Result(或其他)作为参数。这消除了所有的歧义。

    或者,在您的情况下,您可以将isPacketReceived 设置为您的操作的属性,而不是本地变量,然后您可以查看它以确定数据包是否已完全接收,而不是isCancelled

    你后来说:

    我看到completionHandlerjoin() 完成后被调用。

    是的,这是真的。

    但有点担心join 是一个同步方法,根本,(即你正在调用waitUntilAllOperationsAreFinished)。操作队列的目的是让我们可以采用异步模式来处理可能耗时的任务,并将这些东西从主线程中移除。在我们等待操作完成时进行阻塞(特别是如果您从主线程调用 join)似乎会破坏该目的。

    我鼓励您采用异步模式,只需将您的操作添加到队列并在其完成处理程序中启动您需要的任何内容(无论是默认的还是您自己的)。

    【讨论】:

    • 只要把我的操作实现4u。我还看到在 join() 完成后调用了 completionHandler。此外,我可以在调用 completionHandler 之前再次调用 start() ...正如我在这里找到的 developer.apple.com/documentation/foundation/operation/… 似乎无法保证调用处理程序的确切时间。我说的对吗?
    • 目前我检查操作退出状态的解决方案如下: func join() { m_executer.waitUntilAllOperationsAreFinished() if let op = m_operation { if op.isCancelled { print("操作完成: CANCELLED") } else { print("操作完成:正常") } } }
    • “似乎无法保证调用处理程序的确切时间。我对吗?” ...是的,这是真的。这是我经常实现自己的完成处理程序的另一个原因。我可以指定何时调用它以及提供哪些参数。
    猜你喜欢
    • 1970-01-01
    • 2020-02-24
    • 2016-08-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多