如何掌握当前正在执行的NSOperation?

时间:2011-09-07 15:18:07

标签: objective-c multithreading cocoa nsoperation

[NSOperationQueue currentQueue]是否等同于[NSThread currentThread]NSOperation

我有一个相当复杂的域模型,其中繁重的处理发生在调用堆栈的深层次。为了及时取消操作,我需要将NSOperation作为参数传递给每个方法,直到我想要中断更长时间运行的循环。使用线程我可以使用[[NSThread currentThread] isCancelled]所以如果有一个NSOperation的等价物似乎很方便,不幸的是只有看似无用的[NSOperationQueue currentQueue]

6 个答案:

答案 0 :(得分:7)

在swift中提供了一个返回正在运行的操作的扩展

extension NSOperationQueue {
    public var runningOperations: [NSOperation] {
        return operations.filter {$0.executing && !$0.finished && !$0.cancelled}
    }
}

然后你可以拿起第一个

if let operation = aQueue.runningOperations.first {}

答案 1 :(得分:4)

不,没有方法可以找到当前正在执行的操作。

解决问题的两种方法:

  1. 操作是对象。如果你需要对象A与对象B交谈,你需要安排A来引用B。有很多方法可以做到这一点。一种方法是将操作传递给需要了解它的每个对象。另一种是使用授权。第三个是使操作成为传递给每个方法或函数的更大“上下文”的一部分。如果您发现需要将一个对象的引用传递给其他几个对象,只是为了将它引导到最终将使用它的对象,那么您应该考虑重新安排代码。

  2. 让“重吊”方法返回一些传递给调用链的值。您不一定需要使用繁重的方法来调用[currentOperation cancel]来实现目标。实际上,最好让它返回一些值,操作将理解为“工作已完成,现在停止”,因为它可以检查返回值并立即退出而不必在调用-isCancelled时调用一段时间,看看它是否被取消。

答案 2 :(得分:3)

这不是一个好主意。操作通常由队列取消。在操作的main()方法中,你可以定期检查self是否被取消(例如,每次n遍历一个循环,或者在每个主要命令块的开头),如果是,则中止。

要响应取消(例如,某些UI元素与操作或队列的状态相关联),您可以使用键值观察(KVO)让您的控制器观察操作的启动,完成和取消属性(根据需要) ,然后在更新这些键时设置UI的状态(始终在主线程上)。根据JeremyP的评论,重要的是要注意来自操作线程的KVO通知和UI(几乎)总是应该在线程上进行操作,因此您需要使用-performSelectorOnMainThread ...方法当您收到状态更改KVO关于您的操作的注释时更新您的实际用户界面。

你真的想做什么?也就是说,为什么您觉得应用程序的其他部分需要直接了解当前的操作?

答案 3 :(得分:1)

您可以将当前操作存储在线程字典中。请记住在退出之前摆脱它。如果您创建了对象,则可以安全地使用线程dict。

答案 4 :(得分:1)

您可以组合使用[NSOperationQueue currentQueue]& [NSThread currentThread]来实现这一目标。

基本上,您需要遍历currentQueue上的操作并找到在currentThread上运行的操作。

NSOperation不提供对其运行的线程的访问权限,因此您需要自己添加该属性并进行分配。

你可能已经在继承NSOperation并提供一个main,所以在该子类中添加一个'thread'属性:

@interface MyOperation : NSOperation
    @property(nonatomic,strong) NSThread *thread ;
@end

然后,在'main'中将当前线程分配给该属性

myOperation.thread = [NSThread currentThread]

然后您可以添加'currentOperation'方法:

+(MyOperation *)currentOperation
{
    NSOperationQueue *opQueue = [NSOperationQueue currentQueue] ;
    NSThread *currentThread = [NSThread currentThread] ;

    for( MyOperation *op in opQueue.operations ) {
        if( [op isExecuting] && [op respondsToSelector:@selector(thread)] ) {
                if( op.thread == currentThread ) {
                    return ( op ) ;
                }
            }
        }
    }

    return nil ;
}

答案 5 :(得分:0)

您如何知道要取消哪项操作? 当你到达想要取消的点时,只需调用[myQueue operations]并完成操作,直到找到你想要取消的操作。我想如果你有数百万次操作(或数千次),这可能行不通。

[myQueue operations]是线程安全的 - Queue内容的快照。您可以随意潜水,非常快速取消。

另一种方式: NSOperationQueue不是单身人士,所以你可以创建一个Q就可以说200个工作,然后通过获取Q并取消全部取消全部20个。将Q存储在主线程的字典中,然后您可以从dict中获取要取消的作业并将其全部取消。即你有1000种操作,并且在代码中你意识到你不需要某项任务,你就得到那种Q,并查看它取消的工作。