Почему мой подкласс NSOperation никогда не заканчивается?
У меня есть подкласс NSOperation
, который я хочу запустить одновременно.
Мое понимание таково, что для одновременной работы операций:
- мне нужно определить
isConcurrent
, чтобы вернутьYES
. - мне нужно определить метод
start
- мне нужно отправить уведомление KVOs для
isExecuting
иisFinished
, когда это будет сделано. - С помощью
@synthesize
автоматически отправляет соответствующие уведомления KVO при изменении значений дляisExecuting
иisFinished
.
Несмотря на это, у меня есть проверено, что моя очередь никогда не переходит к следующему пункту.
Вот мясо моего кода:
@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 ответа:
Похоже, что все уведомления 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]; } }
См. также:
Как выглядит ваша "очередь"? Вы используете 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;