Why is my NSOperation subclass never finishing?

瘦欲@ 提交于 2019-12-07 10:31:09

问题


I have an NSOperation subclass that I want to run concurrently.

My understanding is that for concurrent operations to work:

  • I need to define isConcurrent to return YES.
  • I need to define the start method
  • I need to send KVOs notification for isExecuting and isFinished when it's done.
  • Using @synthesize will automatically send the appropriate KVO notifications when the values for isExecuting and isFinished are changed.

Despite this, I have verified that my queue never moves on to the next item.

Here's the meat of my code:

@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

What am I missing?

(This is on an iPhone, but I can't imagine that matters.)


回答1:


It looks like whatever KVO notifications @synthesize sends aren't enough for NSOperationQueue to move on.

Sending the notifications manually fixes the problem:

- (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];
    }
}

See also:

  • Why does NSOperation disable automatic key-value observing?



回答2:


What's your "queue" look like? Are you using an NSOperationQueue?

Anyway, I'll try to answer your question with what I understood :P

I would create a delegate for my NSOperation and have KVO take care of calling this.

Say for example your NSOperation class looks like this

@interface MyOperation : NSOperation

@property (assign) id<MyOperationDelegate> delegate;

Your implementation

@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];
}

And finally your protocol

@class MyOperation;
@protocol MyOperationDelegate <NSObject>

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


来源:https://stackoverflow.com/questions/10422883/why-is-my-nsoperation-subclass-never-finishing

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!