为什么我的NSOperation没有取消?

时间:2015-10-29 15:06:28

标签: swift nsoperation

我有这个代码将NSOperation实例添加到队列

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

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

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

operationQueue.cancelAllOperations()

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

我正在viewWillDisappear

执行取消

修改

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

5 个答案:

答案 0 :(得分:3)

  

调用此对象的cancel方法设置此值   财产到是。一旦取消,操作必须移至完成   状态。

     

取消操作不会主动停止接收者的代码   执行。操作对象负责调用此方法   如果方法返回YES,则定期并自行停止。

     

在执行任何操作之前,您应该始终检查此属性的值   努力完成操作的任务,这通常意味着   在自定义主方法的开头检查它。它是   可以在开始执行之前取消操作   或在执行期间的任何时间。因此,检查值   主要方法的开头(并在整个过程中定期开始)   方法)让您在操作时尽快退出   取消。

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
    }
})

答案 1 :(得分:2)

这是因为你做错了。执行后取消操作。 检查此代码,在一个后台线程中执行块。在执行开始之前 - 取消操作,从队列中删除第一个块。

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!

答案 2 :(得分:1)

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

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

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

对于您的特定用例,在此处使用NSOperation是没有意义的,而应该取消正在运行的网络请求。

答案 3 :(得分:1)

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

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

答案 4 :(得分:0)

我不是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
  }
}