我想实现的操作队列中,我有以下情形:
NSOperation A
NSOperation B
NSOperation C
NSOperation D
NSOperationQueue queue
我开始添加A
到queue
。
执行过程中A
我需要得到一些数据, B
,我不能继续A
到B
返回我需要什么。
同样的情况将发生B
取决于C
和C
取决于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];
}
我的问题是,当我有类似3个或4 NSOperations
等待,执行while(!operacao.isFinished && !self.isCancelled){}
我的代码只是冻结,因为那的NSOperation对我很重要没有得到执行,即使如果有更高的优先级。
我试着
添加在执行期间的依赖,但由于我的NSOperation已经运行我似乎并不产生任何影响。
而不是添加操作排队的,我可以做一些事情[operation start]
。 它的工作原理,但取消当前的操作也将取消,我开始其他操作?
我可以这样做while(!operacao.isFinished && !self.isCancelled){[NSThread sleepForTimeInterval:0.001];}
它的工作原理,但这是正确的方法是什么? 也许有更好的解决方案。
在这种情况下如何我可以保证,我想将运行操作和其他人将在后台等待? 什么是解决这个问题的正确方法是什么?
如果有人问我为什么不开始我的队列,因为它的操作将只需要如果某些条件为真,其他前添加的依赖。 我知道,如果我只是在执行时需要其他操作。
谢谢你的时间。
Answer 1:
这里有两种思路为你做作的例子。 我只用了两次手术,但根据需要,你可以将这个概念扩展到任何数量和/或嵌套它们。
示例1:使用大中央调度
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
实施例2:使用本地NSOperationQueue
既然你有工作操作是已经,另一个选择是创建队列为AlphaOperation的属性,然后添加BetaOperation并呼吁waitUntilAllOperationsAreFinished
队列。 这有一个好处,你可以很容易地取消队列的操作时,AlphaOperation被取消,只需通过重写cancel
方法。
@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
Answer 2:
一种方法是从外部操作类,即管理此。 设置A / B / C之间的操作依赖/ D正确地在建立它们。
步骤:(在该方法中被创建这些操作)
1)创建操作A
2)如果通过操作B提供的数据不可用时,创建操作B,使操作A依赖于操作B.即 像operationA.addDependency(operationB);
3)。 重复步骤2为C和D(即B依赖于C和C取决于d,如果需要的话)
4)添加操作队列。 队列将执行基于依赖关系,即。 d,C,B,A。
Answer 3:
尝试使用setCompletionBlock:
是这样的:
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
NSOperation *operationA;
NSOperation *operationB;
//... initialize operationA and operationB however you please ...
[operationA setCompletionBlock:^{
if ([operationA satisfiesSomeCriteria]) {
[queue addOperation:operationB];
}
}];
[queue addOperation:operationA];
当你的操作设置完成块,操作的主要任务是完成或取消后执行。 因此,操作执行工作的结果都可以让你可以决定下一步的操作是否应该被添加到队列中。
Answer 4:
所以基本上你只需要确保在开始下一个之前的第一个完成? 除非你告诉它不要NSOperationQueue将并行运行。 您可以拨打setMaxConcurrentOperationCount:你的操作队列并将其设置为一个基本上把它变成一个串行队列,其中只有一个操作会同时运行。
Answer 5:
一旦的NSOperation是其主要方法,你必须用它去。 没有暂停状态,只完成或取消。
我将落实操作的一个NSCopying这将整个状态复制到一个新的实例。 你将有一个委托方法或块,是能够沟通,这种操作根本无法进入,因为它是从操作B.缺少信息
所以这个过程会去这样的:
- 创建操作A,设置委托
- 你无法继续,委托方法火灾
- 委托创建一个新的操作B,创建操作的副本,将依赖使得A将等待B的完成
- 然后委托取消原运甲
委托里面你必须确保暂停队列,以避免出现竞争状况。 完成以上步骤后,你恢复队列。 在操作中,你会在那里你检查isCancelled实际上没有做任何主更多的工作时,它已经取消了多个地方。
Answer 6:
我认为你是在队列以下错误approach.If每一个操作都有一个优先级,并且它们必须按顺序执行的,为什么不使用4个不同的线程?
取表示的状态(0:无操作完成后,1:一个操作完成时,等等)的实例变量,与病症保护它:
@property(nonatomic,strong) NSCondition* condition;
@property (nonatomic) NSUInteger state;
Initalize一切(状态上以零开始),然后创建具有不同priorities.This 4个不同的线程是用于通过线程A执行的选择的一个示例:
- (void) threadA : (id) sender
{
[condition lock];
while(state!=3)
{
[condition wait];
}
// Do the job here
state=4; // That's kinda useless but useful if in future you
// want another thread that starts doing the job when A ends
[condition unlock];
}
因此,所有获取你想要的顺序执行。
编辑
你能做到这一点我在这里做的相当,但使用NSOperationQueue:
NSOperationQueue* queue=[NSOperationQueue new];
[queue setMaxConcurrentOperationCount: 4];
[queue addOperation: [[NSInvocationOperation alloc]initWithTarget: self selector: @selector(threadA:) object: nil]]
应该说你跟随了错误的方法,我的意思是,你不应该使用一个队列,1为maxConcurrentOperationCount。 主队列有这个值设置为1,这就是你的烦恼的原因。
Answer 7:
正如您看到的,你不能真正做到这一点具有相关性,因为操作开始时只影响 - 如果你不知道,直到主一个正在运行则需要在子操作,所以这是没有好。 你不能用一个单一的操作队列解决这个问题。
但是,因为你已经在操作队列运行,没有必要进一步操作添加到队列中。 只是就地同步执行。 你必须等待他们反正回来,为什么不呢?
文章来源: NSOperation - Forcing an operation to wait others dynamically