NSOperation队列优先级不按预期工作

时间:2015-08-12 17:38:36

标签: ios objective-c nsoperation

当我需要管理操作的优先级时,我正在研究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顺序,但是,我专门设置了两个操作的优先级,那么为什么第一个操作完成第一个?它假设是在第二个之后(具有更高的优先级)。

4 个答案:

答案 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的特定顺序,因为您无法保证您的操作将按优先级顺序执行。

documentation

  

您应该仅根据需要使用优先级值来对亲属进行分类   非依赖性操作的优先级。优先级值不应该是   用于在不同操作之间实现依赖管理   对象。如果需要在操作之间建立依赖关系,请使用   而是addDependency:方法。

如果您需要按特定顺序执行操作,因为其中一个操作依赖于另一个操作,则应使用addDependency: NSOperation方法。 所以你应该做这样的事情:

[firstOperation addDependency: secondOperation];

这可以保证firstOperation之后执行secondOperation