NSOperation - 强制操作动态等待其他操作

Raf*_*ael 27 objective-c nsoperation nsthread nsoperationqueue ios

我正在尝试实现一个操作队列,我有以下场景:

NSOperation A
NSOperation B
NSOperation C
NSOperation D
NSOperationQueue queue
Run Code Online (Sandbox Code Playgroud)

我开始加入Aqueue.

在执行期间,A我需要从中获取一些数据B,我无法继续,A直到B返回我需要的内容.

B取决于CC取决于相同的情况将发生D.

为了管理这个,每个NSOperation我都有这个代码:

NSOperation *operation; //This can be A, B, C, D or any other NSOperation

[self setQueuePriority:NSOperationQueuePriorityVeryLow]; //Set the current NSOperation with low priority

[queue addOperation: operation]; //Add the operation that I want to the queue

while(!operation.isFinished && !self.isCancelled){} //I need to wait the operation that I depend before moving on with the current operation

[self setQueuePriority:NSOperationQueuePriorityNormal]; //After the while, the other operation finished so I return my priority to normal and continue

if(self.isCancelled){ //If I get out of the while because the current operation was cancelled I also cancel the other operation.
[operation cancel];          
}
Run Code Online (Sandbox Code Playgroud)

我的问题是,当我有3或4 NSOperations等等的东西等待并执行while(!operacao.isFinished && !self.isCancelled){}我的代码时冻结,因为对我来说重要的NSOperation不会被执行,即使它具有更高的优先级.

我尝试了什么

  • 在执行期间添加依赖性,但由于我的NSOperation已经运行,我似乎没有任何影响.

  • 我可以做一些事情,而不是将操作添加到队列中[operation start].它有效,但是取消当前的操作也会取消我开始的其他操作吗?

  • 我可以做点什么while(!operacao.isFinished && !self.isCancelled){[NSThread sleepForTimeInterval:0.001];}.它有效,但这是正确的方法吗?也许有更好的解决方案.

在这种情况下,我怎么能保证我想要的操作会运行而其他人会在后台等待?解决这个问题的正确方法是什么?

如果有人质疑我为什么不在启动队列之前添加依赖项,因为只有在某些条件为真时,操作才需要另一个操作.我会知道我是否只在执行期间需要其他操作.

谢谢你的时间.

rol*_*and 37

通过人为的例子,这里有两个想法.我只使用了两个操作,但您可以将概念扩展为任意数字和/或根据需要嵌套它们.

示例1:使用Grand Central Dispatch

GCD提供轻量级的"调度组",允许您明确地对任务进行排序,然后等待完成.在这种情况下,AlphaOperation会创建一个组并输入它,然后启动BetaOperation,这completionBlock会导致组被遗弃.当你调用时dispatch_group_wait,当前线程会阻塞,直到进入组的次数等于离开它的次数(很像保留计数).isCancelled在任何可能长时间运行的任务之后,不要忘记检查操作的状态.

@interface BetaOperation : NSOperation
@end
@implementation BetaOperation
- (void)main
{
    NSLog(@"beta operation finishing");
}
@end

@interface AlphaOperation : NSOperation
@end
@implementation AlphaOperation
- (void)main
{
    dispatch_group_t group = dispatch_group_create();
    dispatch_group_enter(group);

    BetaOperation *betaOperation = [[BetaOperation alloc] init];
    betaOperation.completionBlock = ^{
        dispatch_group_leave(group);
    };

    [betaOperation start];

    dispatch_group_wait(group, DISPATCH_TIME_FOREVER);

    if ([self isCancelled])
        return;

    NSLog(@"alpha operation finishing");
}
@end

@implementation AppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    dispatch_async(dispatch_get_main_queue(), ^{
        AlphaOperation *operation = [[AlphaOperation alloc] init];
        [operation start];
    });

    return YES;
}

@end
Run Code Online (Sandbox Code Playgroud)

示例2:使用本地NSOperationQueue

由于您已经在进行工作操作,因此另一个选择是将队列创建为AlphaOperation的属性,然后添加BetaOperation并调用waitUntilAllOperationsAreFinished队列.这样做的另一个好处是,只需覆盖cancel方法,即可在取消AlphaOperation时轻松取消队列的操作.

@interface BetaOperation : NSOperation
@end
@implementation BetaOperation
- (void)main
{
    NSLog(@"beta operation finishing");
}
@end

@interface AlphaOperation : NSOperation
@property (strong) NSOperationQueue *queue;
@end
@implementation AlphaOperation
- (void)main
{
    self.queue = [[NSOperationQueue alloc] init];

    BetaOperation *betaOperation = [[BetaOperation alloc] init];
    [self.queue addOperation:betaOperation];
    [self.queue waitUntilAllOperationsAreFinished];

    if ([self isCancelled])
        return;

    NSLog(@"alpha operation finishing");
}

- (void)cancel
{
    [super cancel];

    [self.queue cancelAllOperations];
}
@end

@implementation AppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    dispatch_async(dispatch_get_main_queue(), ^{
        AlphaOperation *operation = [[AlphaOperation alloc] init];
        [operation start];
    });

    return YES;
}

@end
Run Code Online (Sandbox Code Playgroud)


小智 6

一种方法是从操作类外部管理它,即.在创建A/B/C/D时正确设置操作依赖关系.

步骤:(在创建这些操作的方法中)

1)创建操作A.

2)如果操作B提供的数据不可用,则创建操作B,并使操作A依赖于操作B. 就像是operationA.addDependency(operationB);

3).对C和D重复步骤2(即B取决于C,C取决于D,如果需要)

4)将操作添加到队列中.队列将基于依赖性执行,即.D,C,B,A