完成每次都不会调用并发NSOperation块

时间:2015-12-05 02:56:41

标签: ios objective-c multithreading nsoperation nsoperationqueue

我想运行一个并发的NSOperation。出于这个原因,我扩展了NSOperation类并重写了开始和结束方法。它看起来像这样:

#import "AVFrameConversionOP.h"


@implementation AVFrameConversionOP //extends NSOperation

- (void)start
{

    [self willChangeValueForKey:@"isFinished"];
    _isFinished = NO;
    [self didChangeValueForKey:@"isFinished"];

    // Begin
    [self willChangeValueForKey:@"isExecuting"];
    _isExecuting = YES;
    [self didChangeValueForKey:@"isExecuting"];

    if (_isCancelled == YES) {
        NSLog(@"** OPERATION CANCELED **");
        [self willChangeValueForKey:@"isFinished"];
        _isFinished = YES;
        [self didChangeValueForKey:@"isFinished"];
        return;
    } 

    [self performTask];
    [self finish];

}

- (void)finish
{

    [self willChangeValueForKey:@"isExecuting"];
    [self willChangeValueForKey:@"isFinished"];

    _isExecuting = NO;
    _isFinished = YES;

    [self didChangeValueForKey:@"isExecuting"];
    [self didChangeValueForKey:@"isFinished"];

    NSLog(@"operationfinished, _isFinished is %d", _isFinished);

    if (_isCancelled == YES)
    {
        NSLog(@"** OPERATION CANCELED **");
    }
}

- (void)performTask
{
    //The task is performed here
    sleep(0.1); //This is just for demonstration purposes
}
@end

我已在viewDidLoad方法的主视图控制器中为此NSOperation定义了完成块:

- (void)viewDidLoad {

NSLog(@"viewDidLoad!");
[super viewDidLoad];

static int counter = 0;


_frameConvOP = [[AVFrameConversionOP alloc] init]; //Initializing the modified NSOperation class
__weak typeof(self) weakSelf = self;
_frameConvOP.completionBlock = ^ {
    counter++;
    //NSLogs don't seem to work here
    /*if(counter>1){
         exit(-1); //Never happens because counter only ever becomes =1
    }*/

};
[[VideoPreviewer instance] setNSOperation:_frameConvOP]; //This is where I send the NSOperation object to the class where I'm using it

}

我通过在循环中执行[frameConvOP start]来启动NSOperation。每次解码帧时都会连续调用它,这就是说它经常被调用。我可以看到NSOperation的finishstart方法经常通过日志调用。并且这些方法中的函数也被正确调用。但是,完成阻止内的NSLogs未被记录。我在完成块中放置了一个exit(-1),应用程序崩溃了,但NSLogs从未出现过。所以我在那里放了一个静态计数器,它只增加到1.所以完成块只被调用一次。

有人可以解释为什么只调用一次完成块吗?是因为我(错误地)处理_isFinished_isExecuting的KVO的方式?当_isFinished设置为YES时应该调用完成块,据我所知,我在完成块中执行此操作。并且应该非常频繁地调用终点块。

感谢任何帮助,指导或指示。如果我有任何错误或者我在帖子中不太清楚,请告诉我。

谢谢,

1 个答案:

答案 0 :(得分:0)

来自NSOperation class reference

  

操作对象是单击对象 - 也就是说,它执行一次任务,不能再用来执行它。

不允许您在单个操作对象上多次调用-start

另一方面,在-finish方法中,您需要正确嵌套-willChange...-didChange...来电。也就是说,您需要按-didChange...来电的相反顺序呼叫-willChange...

[self willChangeValueForKey:@"isExecuting"];
[self willChangeValueForKey:@"isFinished"];

_isExecuting = NO;
_isFinished = YES;

[self didChangeValueForKey:@"isFinished"];
[self didChangeValueForKey:@"isExecuting"];