在单个 NSOperationQueue iOS 中管理多个操作,例如暂停/恢复单个操作

Posted

技术标签:

【中文标题】在单个 NSOperationQueue iOS 中管理多个操作,例如暂停/恢复单个操作【英文标题】:Managing Multiple Operations in Single NSOperationQueue iOS like Pause/Resume single Operation 【发布时间】:2015-03-13 19:58:09 【问题描述】:

在我的代码中,我想在队列中单独处理操作,并能够暂停和恢复队列中的操作操作。我该如何实现呢?

让我简要解释一下我的问题,我使用下面的代码通过子类 NSOperation 创建操作并将此操作添加到 NSOperationQueue。

@interface MyLengthyOperation: NSOperation
@end

@implementation MyLengthyOperation
- (void)main

    // a lengthy operation
    @autoreleasepool 
    
        for (int i = 0 ; i < 10000 ; i++) 
        

            // is this operation cancelled?
            if (self.isCancelled)
            break;

            NSLog(@"%f", sqrt(i));
        
    

@end

我已经创建了上面的操作,我用

调用它
NSOperationQueue *myQueue = [[NSOperationQueue alloc] init];
myQueue.name = @"Download Queue";
myQueue.maxConcurrentOperationCount = 4;
[myQueue addOperation:operation];

现在我想暂停并恢复我的操作。假设循环在 6786 上,我按下了暂停按钮,那么队列应该暂停这个操作,当我按下开始时,它应该从 6786 开始。

我想控制队列中的多个操作。我该怎么做?

我查看了[queue setSuspended:YES]; - 这将阻止队列添加新操作,但我想控制队列中现有的操作。

等待您的答复。

提前致谢!

【问题讨论】:

【参考方案1】:

没有暂停特定 NSOperation 的内置功能,如果您想要这种行为,那么您需要自己构建它。

您可以使用NSCondition 来执行此操作 -

@interface MyLengthyOperation: NSOperation

@property (atomic) BOOL paused;
@property (nonatomic,strong) NSCondition *pauseCondition;

@end

@implementation MyLengthyOperation

-(instancetype) init 
    if (self=[super init]) 
        self.pauseCondition=[NSCondition new];
    
    return self;


- (void)main

    // a lengthy operation
    @autoreleasepool 
    
        for (int i = 0 ; i < 10000 ; i++) 
        

            // is this operation cancelled?
            if (self.isCancelled)
            break;

            [self.pauseCondition lock];
            while (self.paused) 
                [self.pauseCondition wait];
            
            NSLog(@"%f", sqrt(i));
            [self.pauseCondition unlock];
        
    


-(void)pause 
    [self.pauseCondition lock];
    self.paused=YES;
    [self.pauseCondition signal];
    [self.pauseCondition unlock];


-(void)resume 
     [self.pauseCondition lock];
    self.paused=NO;
    [self.pauseCondition signal];
    [self.pauseCondition unlock];

777441end

然后你可以说[myOperation pause][myOperation resume]

【讨论】:

检查您的答案后,我认为这应该可以解决问题,我一定会尝试上面的代码,希望它能解决我的问题,非常感谢@Paulw11 的快速详细回答.真的很欣赏它!【参考方案2】:

NSOperation 不支持开箱即用的暂停操作,您必须自己实现。一种策略是使用条件变量(参见 Paulw11 的答案)。您甚至可以使用单个条件变量同时控制多个操作。

但如果您想暂停许多并发操作,这种方法可能会出现问题。每个暂停的操作都会阻塞一个线程。使用条件变量可以确保那些被阻塞的线程不使用任何 CPU,但这些线程的内存不能被重用。根据暂停线程的数量以及在此期间您还想做什么,这种内存使用可能会出现问题。 Apple 将其列为要避免的事情。

另一种方法是“拆分”操作。因此,当您想暂停时,您首先暂停队列,然后让每个操作排队一个新的操作对象,该对象从它停止的地方开始。这当然需要更多的改变。

在您的示例中,您将为您的操作子类提供一个属性 firstNumber 并从该属性开始循环,而不是从零开始。然后在暂停时创建一个新操作,将当前循环索引作为 firstNumber 并将其加入队列。

这不仅为您提供了在队列暂停时不阻塞任何线程的优势。此外,您还可以实现一个持久队列,将挂起的操作保存到磁盘并在下次应用启动时恢复它们。

【讨论】:

以上是关于在单个 NSOperationQueue iOS 中管理多个操作,例如暂停/恢复单个操作的主要内容,如果未能解决你的问题,请参考以下文章

在 iOS 中上传时出现 NSOperationQueue(ASINetworkQueue) 问题

(iOS) dispatch_async() 与 NSOperationQueue

使用 NSOperationQueue 执行 iOS 应用程序初始化

iOS 使用 NSOperationQueue 和 AFNetworking 实现多下载功能

NSOperationQueue 和并发操作

NSOperationQueue 问题