У меня есть NSOperationQueue, который содержит 2 NSOperations и настроен на их выполнение один за другим, установив setMaxConcurrentOperationCount
в 1.
Одной из операций является стандартная не параллельная операция (просто метод main
), которая синхронно извлекает некоторые данные из Интернета (разумеется, в отдельном потоке операций). Другая операция - это параллельная операция, так как мне нужно использовать некоторый код, который должен выполняться асинхронно.
Проблема в том, что я обнаружил, что параллельная операция работает, только если она добавлена в очередь первой. Если это происходит после каких-либо непараллельных операций, то, как ни странно, метод start
вызывается нормально, но после того, как этот метод заканчивается, и я настроил свое соединение для обратного вызова метода, он никогда этого не сделает. Никакие дальнейшие операции в очереди не выполняются после. Это как если бы оно зависало после возврата метода start, и никакие обратные вызовы из любых URL-соединений не вызывались!
Если моя параллельная операция помещается первой в очередь, то все работает нормально, асинхронные обратные вызовы работают, а последующая операция выполняется после ее завершения. Я совсем не понимаю!
Вы можете увидеть тестовый код для моей параллельной NSOperation ниже, и я почти уверен, что он твердый.
Любая помощь будет принята с благодарностью!
Наблюдение за главной нитью:
Я только что обнаружил, что если параллельная операция сначала выполняется в очереди, то метод [start]
вызывается в главном потоке. Однако, если он не является первым в очереди (если он идет после одновременного или не одновременного), то метод [start]
не вызывается в главном потоке. Это кажется важным, поскольку это соответствует образцу моей проблемы. Что может быть причиной этого?
Код одновременной работы NSO:
@interface ConcurrentOperation : NSOperation {
BOOL executing;
BOOL finished;
}
- (void)beginOperation;
- (void)completeOperation;
@end
@implementation ConcurrentOperation
- (void)beginOperation {
@try {
// Test async request
NSURLRequest *r = [[NSURLRequest alloc] initWithURL:[NSURL URLWithString:@"http://www.google.com"]];
NSURLConnection *c = [[NSURLConnection alloc] initWithRequest:r delegate:self];
[r release];
} @catch(NSException * e) {
// Do not rethrow exceptions.
}
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
NSLog(@"Finished loading... %@", connection);
[self completeOperation];
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
NSLog(@"Finished with error... %@", error);
[self completeOperation];
}
- (void)dealloc {
[super dealloc];
}
- (id)init {
if (self = [super init]) {
// Set Flags
executing = NO;
finished = NO;
}
return self;
}
- (void)start {
// Main thread? This seems to be an important point
NSLog(@"%@ on main thread", ([NSThread isMainThread] ? @"Is" : @"Not"));
// Check for cancellation
if ([self isCancelled]) {
[self completeOperation];
return;
}
// Executing
[self willChangeValueForKey:@"isExecuting"];
executing = YES;
[self didChangeValueForKey:@"isExecuting"];
// Begin
[self beginOperation];
}
// Complete Operation and Mark as Finished
- (void)completeOperation {
BOOL oldExecuting = executing;
BOOL oldFinished = finished;
if (oldExecuting) [self willChangeValueForKey:@"isExecuting"];
if (!oldFinished) [self willChangeValueForKey:@"isFinished"];
executing = NO;
finished = YES;
if (oldExecuting) [self didChangeValueForKey:@"isExecuting"];
if (!oldFinished) [self didChangeValueForKey:@"isFinished"];
}
// Operation State
- (BOOL)isConcurrent { return YES; }
- (BOOL)isExecuting { return executing; }
- (BOOL)isFinished { return finished; }
@end
Код очереди
// Setup Queue
myQueue = [[NSOperationQueue alloc] init];
[myQueue setMaxConcurrentOperationCount:1];
// Non Concurrent Op
NonConcurrentOperation *op1 = [[NonConcurrentOperation alloc] init];
[myQueue addOperation:op1];
[op1 release];
// Concurrent Op
ConcurrentOperation *op2 = [[ConcurrentOperation alloc] init];
[myQueue addOperation:op2];
[op2 release];