当我需要管理操作的优先级时,我正在研究NSOperation
类并尝试模拟一种情况。
请考虑以下代码:
@implementation MyOperation // First custom NSOperation class
- (void)main {
@autoreleasepool {
NSLog(@"First operation start");
}
}
@implementation MySecondOperation // Second custom NSOperation class
- (void)main {
@autoreleasepool {
NSLog(@"Second operation start");
}
}
@implementation ViewController // Other class using NSOperations
- (void)viewDidLoad {
NSOperationQueue *myQueue = [NSOperationQueue new];
MyOperation *firstOperation = [MyOperation new];
MySecondOperation *secondOperation = [MySecondOperation new];
[firstOperation setQueuePriority:NSOperationQueuePriorityLow];
[secondOperation setQueuePriority:NSOperationQueuePriorityHigh];
[myQueue addOperation:secondOperation];
[myQueue addOperation:firstOperation];
}
代码非常简单。但是,您会惊讶地看到输出:
2015-08-12 20:32:09.433 NSOperationTesting[1181:39809] First operation start
2015-08-12 20:32:09.433 NSOperationTesting[1181:39811] Second operation start
优先级较低的NSOperation在运行前启动,具有较高的优先级。我知道,NSOperationQueue工作在FIFO顺序,但是,我专门设置了两个操作的优先级,那么为什么第一个操作完成第一个?它假设是在第二个之后(具有更高的优先级)。
答案 0 :(得分:4)
尝试将myQueue.maxConcurrentOperationCount设置为1.我的猜测是它正在同时运行您的操作。
答案 1 :(得分:4)
不要相信NSLog
。您只添加了两个操作,它们同时执行。我修改并运行了您的代码,以下示例显示高优先级操作在优先级较低的操作之前执行。
NSOperationQueue *myQueue = [NSOperationQueue new];
NSMutableArray *operations = [NSMutableArray new];
for (int i = 0; i < 10000; i++) {
MyOperation *firstOperation = [MyOperation new];
MySecondOperation *secondOperation = [MySecondOperation new];
[firstOperation setQueuePriority:NSOperationQueuePriorityLow];
[secondOperation setQueuePriority:NSOperationQueuePriorityHigh];
[operatons addObject:firstOperation];
[operatons addObject:secondOperation];
}
[myQueue addOperations:operations waitUntilFinished:NO];
输出:
2015-08-12 19:47:30.826 oper[1137:31464] Second operation start
2015-08-12 19:47:30.826 oper[1137:31487] Second operation start
2015-08-12 19:47:30.826 oper[1137:31465] Second operation start
...
2015-08-12 19:47:36.443 oper[1137:31491] First operation start
2015-08-12 19:47:36.443 oper[1137:31491] First operation start
2015-08-12 19:47:36.443 oper[1137:31491] First operation start
编辑:
正如Rob所说,NSOperation
优先级并不能保证执行的顺序。如果要等到操作完成后再启动另一个操作,请使用addDependency:
方法。
答案 2 :(得分:2)
就我而言,与operation.qualityOfService
相比,财产operation.queuePriority
给了我更好的结果。你可能想尝试一下。
我使用operation.qualityOfService = NSQualityOfServiceUserInteractive
进行高优先级操作,operation.qualityOfService = NSQualityOfServiceDefault
用于普通优先级操作,并按预期工作。
您可以使用以下代码对此进行测试。
#define kMaxSeconds 5
#define kSleepTime 1
@interface ViewController ()
@property (nonatomic, assign) NSInteger currentCount;
@property (nonatomic, strong) NSOperationQueue* operationQueue;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.currentCount = 0;
[self addOperationInQueueWithQuality:NSQualityOfServiceUserInteractive];
[self addOperationInQueueWithQuality:NSQualityOfServiceDefault];
[self addOperationInQueueWithQuality:NSQualityOfServiceUserInteractive];
[self addOperationInQueueWithQuality:NSQualityOfServiceDefault];
[self addOperationInQueueWithQuality:NSQualityOfServiceUserInteractive];
}
- (void)addOperationInQueueWithQuality:(NSQualityOfService)quality{
if(!self.operationQueue){
self.operationQueue = [NSOperationQueue new];
}
self.currentCount++;
NSInteger blockNumber = self.currentCount;
NSBlockOperation* blockOperation = [NSBlockOperation blockOperationWithBlock:^{
for(int i=0; i < kMaxSeconds; i++){
NSMutableString* str = [NSMutableString new];
for(int j = 0; j < self.currentCount+1; j++){
if(j == blockNumber){
[str appendString:@" |"];
}else{
[str appendString:@" ."];
}
}
NSLog(@"%@", [str copy]);
sleep(kSleepTime);
}
}];
blockOperation.qualityOfService = quality;
blockOperation.completionBlock = ^{
NSLog(@"Block operation %ld completed", blockNumber);
};
[self.operationQueue addOperation:blockOperation];
}
@end
答案 3 :(得分:1)
您不应该使用或依赖QueuePriority
来设置执行operations
的特定顺序,因为您无法保证您的操作将按优先级顺序执行。
您应该仅根据需要使用优先级值来对亲属进行分类 非依赖性操作的优先级。优先级值不应该是 用于在不同操作之间实现依赖管理 对象。如果需要在操作之间建立依赖关系,请使用 而是
addDependency:
方法。
如果您需要按特定顺序执行操作,因为其中一个操作依赖于另一个操作,则应使用addDependency:
NSOperation
方法。
所以你应该做这样的事情:
[firstOperation addDependency: secondOperation];
这可以保证firstOperation
之后执行secondOperation
。