为什么我的NSOperation子类永远不会完成?

时间:2012-05-02 22:58:41

标签: cocoa-touch key-value-observing nsoperation

我有一个NSOperation子类,我想同时运行。

我的理解是,要使并发操作起作用:

  • 我需要定义isConcurrent才能返回YES
  • 我需要定义start方法
  • 我需要在isExecutingisFinished完成后发送KVO通知。
  • @synthesizeisExecuting的值发生变化时,使用isFinished会自动发送相应的KVO通知。

尽管如此,我已经确认我的队列永远不会移动到下一个项目。

以下是我的代码的内容:

@interface MyOperation()

@property (readwrite) BOOL isExecuting;
@property (readwrite) BOOL isFinished;

@end

@implementation MyOperation

- (void)start
{
    @autoreleasepool {
        self.isExecuting = YES;
        self.HTTPOperation = [[AFHTTPRequestOperation alloc] initWithRequest: URLRequest];

        _HTTPOperation.completionBlock = [^{
            [self completed];

            self.isExecuting = NO;
            self.isFinished = YES;
        } copy];

        [_HTTPOperation start];
    }
}

- (BOOL)isConcurrent
{
    return YES;
}

- (void)completed
{
}

@end

我错过了什么?

(这是在iPhone上,但我无法想象这很重要。)

2 个答案:

答案 0 :(得分:4)

看起来任何KVO通知@synthesize发送的内容都不足以让NSOperationQueue继续前进。

手动发送通知可解决问题:

- (void)start
{
    @autoreleasepool {
        [self willChangeValueForKey:@"isExecuting"];
        self.isExecuting = YES;
        [self didChangeValueForKey:@"isExecuting"];

        NSURLRequest *URLRequest = [self buildRequest];
        if (!URLRequest) {
            [self willChangeValueForKey:@"isFinished"];
            [self willChangeValueForKey:@"isExecuting"];
            _isExecuting = NO;
            _isFinished = YES;
            [self didChangeValueForKey:@"isExecuting"];
            [self didChangeValueForKey:@"isFinished"];
            return;
        }

        self.HTTPOperation = [[AFHTTPRequestOperation alloc] initWithRequest: URLRequest];

        _HTTPOperation.completionBlock = [^{
            [self completed];

            [self willChangeValueForKey:@"isFinished"];
            [self willChangeValueForKey:@"isExecuting"];
            _isExecuting = NO;
            _isFinished = YES;
            [self didChangeValueForKey:@"isExecuting"];
            [self didChangeValueForKey:@"isFinished"];
        } copy];

        [_HTTPOperation start];
    }
}

另见:

答案 1 :(得分:1)

你的“队列”是什么样的?你在使用NSOperationQueue吗?

无论如何,我会尝试用我理解的方式回答你的问题:P

我会为我的NSOperation创建一个委托,让 KVO 负责调用它。

例如,您的 NSOperation 类看起来像这样

@interface MyOperation : NSOperation

@property (assign) id<MyOperationDelegate> delegate;

您的实施

@synthesize delegate;
@synthesize error;

    -(id)init{
    self = [super init];
    if(self){
        [self addObserver:self forKeyPath:@"isFinished" 
                  options:NSKeyValueObservingOptionNew 
                  context:NULL];
    }
    return self;
}

-(void)dealloc{
    [self removeObserver:self forKeyPath:@"isFinished"];
    [super dealloc];
}

-(void)observeValueForKeyPath:(NSString *)keyPath 
                     ofObject:(id)object change:(NSDictionary *)change context:(void *)context{

    if([keyPath isEqualToString:@"isFinished"] == YES){
    if([self isCancelled] == NO){
        if(delegate != nil && [delegate respondsToSelector:@selector(operationComplete:)]){
            [delegate taskComplete:self];
        }
    }else{
        if(delegate != nil && [delegate respondsToSelector:@selector(operationCancelled)]){
            [delegate taskCancelled];
        }
    }
}

}

-(void)main{
    [NSException exceptionWithName:kTaskException 
                            reason:@"Only to be used with subclass" 
                          userInfo:nil];
}

最后你的协议

@class MyOperation;
@protocol MyOperationDelegate <NSObject>

@optional
-(void)operationComplete:(MyOperation*)operation;
-(void)operationCancelled;