为什么我的 NSOperation 没有取消?

Why my NSOperation is not cancelling?

我有这段代码可以将 NSOperation 实例添加到队列

let operation = NSBlockOperation()
operation.addExecutionBlock({
    self.asyncMethod() { (result, error) in
        if operation.cancelled {
            return
        }

        // etc
    }
})
operationQueue.addOperation(operation)

当用户离开触发上述代码的视图时,我取消操作

operationQueue.cancelAllOperations()

测试取消时,我 100% 确定取消在异步方法 returns 之前执行,因此我希望 operation.cancelled 为真。不幸的是,这并没有发生,我无法理解为什么

我正在 viewWillDisappear

执行取消

编辑

asyncMethod 包含在不同线程中运行的网络操作。这就是回调存在的原因:处理网络操作 returns。网络操作深入 class 层次结构,但我想在根级别处理 NSOperations。

Calling the cancel method of this object sets the value of this property to YES. Once canceled, an operation must move to the finished state.

Canceling an operation does not actively stop the receiver’s code from executing. An operation object is responsible for calling this method periodically and stopping itself if the method returns YES.

You should always check the value of this property before doing any work towards accomplishing the operation’s task, which typically means checking it at the beginning of your custom main method. It is possible for an operation to be cancelled before it begins executing or at any time while it is executing. Therefore, checking the value at the beginning of your main method (and periodically throughout that method) lets you exit as quickly as possible when an operation is cancelled.

import Foundation

let operation1 = NSBlockOperation()
let operation2 = NSBlockOperation()
let queue = NSOperationQueue()
operation1.addExecutionBlock { () -> Void in
    repeat {
        usleep(10000)
        print(".", terminator: "")
    } while !operation1.cancelled
}
operation2.addExecutionBlock { () -> Void in
    repeat {
        usleep(15000)
        print("-", terminator: "")
    } while !operation2.cancelled
}
queue.addOperation(operation1)
queue.addOperation(operation2)
sleep(1)
queue.cancelAllOperations()

在操场上试试这个简单的例子。

如果运行另一个异步代码真的很重要,试试这个

operation.addExecutionBlock({
if operation.cancelled {
            return
        }    
self.asyncMethod() { (result, error) in


        // etc
    }
})

我不是 100% 确定您在寻找什么,但也许您需要的是将操作作为参数传递到 asyncMethod() 并在其中测试取消状态?

operation.addExecutionBlock({
  asyncMethod(operation) { (result, error) in
  // Result code
  }
})
operationQueue.addOperation(operation)

func asyncMethod(operation: NSBlockOperation, fun: ((Any, Any)->Void)) {
  // Do stuff...
  if operation.cancelled {
    // Do something...
    return // <- Or whatever makes senes
  }
}

是因为你做事不对。执行后取消操作。 检查此代码,块在一个后台线程中执行。执行开始前——操作取消,从队列中移除第一个块。

Swift 4

let operationQueue = OperationQueue()
operationQueue.qualityOfService = .background

let ob1 = BlockOperation {
    print("ExecutionBlock 1. Executed!")
}

let ob2 = BlockOperation {
    print("ExecutionBlock 2. Executed!")
}

operationQueue.addOperation(ob1)
operationQueue.addOperation(ob2)

ob1.cancel()

// ExecutionBlock 2. Executed!

Swift 2

let operationQueue = NSOperationQueue()
operationQueue.qualityOfService = .Background

let ob1 = NSBlockOperation()
ob1.addExecutionBlock {
    print("ExecutionBlock 1. Executed!")
}

let ob2 = NSBlockOperation()
ob2.addExecutionBlock {
    print("ExecutionBlock 2. Executed!")
}

operationQueue.addOperation(ob1)
operationQueue.addOperation(ob2)

ob1.cancel()

// ExecutionBlock 2. Executed!

操作不会等待您的 asyncMethod 完成。因此,如果将其添加到队列中,它会立即 returns。这是因为您将异步网络操作包装在异步 NSOperation.

NSOperation 旨在提供更高级的异步处理,而不是仅仅调用 performSelectorInBackground。这意味着 NSOperation 用于在后台进行复杂而冗长的 运行 操作而不阻塞主线程。一个常用NSOperation的好文章可以在这里找到:

http://www.raywenderlich.com/19788/how-to-use-nsoperations-and-nsoperationqueues

对于您的特定用例,在这里使用 NSOperation 没有意义,您应该取消您的 运行 网络请求。

将异步函数放入带有 NSBlockOperation 的块中没有意义。您可能想要的是 NSOperation 的适当 子类 作为执行异步工作负载的并发操作。然而,正确地 NSOperation 子类化并不像它应该的那么容易。

您可以在此处 reusable subclass for NSOperation 查看示例实现。