首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >并发与非并发NSOperations排队问题

并发与非并发NSOperations排队问题
EN

Stack Overflow用户
提问于 2009-10-29 09:08:28
回答 3查看 5.4K关注 0票数 5

我有一个NSOperationQueue,它包含2个NSOperations,并通过将setMaxConcurrentOperationCount设置为1来依次执行它们。

其中一个操作是一个标准的非并发操作(只是一个main方法),它同步地从web (当然是在单独的操作线程上)检索一些数据。另一个操作是并发操作,因为我需要使用一些必须异步运行的代码。

问题是,我发现只有先将并发操作添加到队列中才能工作。如果它是在任何非并发操作之后出现的,那么奇怪的是,start方法会被调用很好,但是在该方法结束之后,我已经设置了我的连接来回调一个方法,它从来没有这样做过。之后将不再执行队列中的其他操作。就好像它在start方法返回后挂起,并且没有调用任何url连接的回调!

如果我的并发操作首先放在队列中,那么所有操作都能正常工作,异步回调工作并在完成后执行后续操作。我一点也不明白!

您可以在下面看到我的并发NSOperation的测试代码,我很确定它是可靠的。

任何帮助都将不胜感激!

主线程观察:

我刚刚发现,如果并发操作首先出现在队列上,那么在主线程上调用[start]方法。但是,如果它不是队列中的第一个(如果它是在并发或非并发之后),那么主线程上不会调用[start]方法。这似乎很重要,因为它符合我的问题的模式。这是什么原因?

并发NSOperation代码:

代码语言:javascript
复制
@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

排队码

代码语言:javascript
复制
// 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];
EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2009-10-29 13:37:39

我发现问题出在哪里了!

Dribin的这两篇无价文章非常详细地描述了并发操作,以及雪豹和iPhone SDK在异步调用需要运行循环的东西时引入的问题。

http://www.dribin.org/dave/blog/archives/2009/05/05/concurrent_operations/ http://www.dribin.org/dave/blog/archives/2009/09/13/snowy_concurrent_operations/

感谢克里斯·苏特为我指明了正确的方向!

它的关键是确保我们调用主线程的start方法:

代码语言:javascript
复制
- (void)start {

    if (![NSThread isMainThread]) { // Dave Dribin is a legend!
        [self performSelectorOnMainThread:@selector(start) withObject:nil waitUntilDone:NO];
        return;
    }

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

    // Start asynchronous API

}
票数 10
EN

Stack Overflow用户

发布于 2009-10-29 11:25:11

您的问题很可能与NSURLConnection有关。NSURLConnection依赖于运行某个模式的运行循环(通常只是默认模式)。

对于您的问题,有许多解决方案:

  1. 确保此操作仅在主线程上运行。如果您在OS上执行此操作,您可能希望检查它在所有运行循环模式(例如,模式模式和事件跟踪模式)中所做的事情,但我不知道iPhone.
  2. 创建和管理您自己的线程是什么。
  3. 调用-NSURLConnection scheduleInRunLoop:forMode:并传入主线程或您所知道的另一个线程。如果您这样做,您可能希望调用-NSURLConnection unscheduleInRunLoop:forMode:第一,否则您可能在多个线程中接收数据(或者至少文档似乎是这样建议的)。
  4. 使用类似于+NSData dataWithContentsOfURL:options:error:这也将简化您的操作,因为您可以在#4: use +NSURLConnection sendSynchronousRequest:returningResponse:error:.

上使它成为一个非并发操作。

如果你能逃脱它,做第4或#5。

票数 6
EN

Stack Overflow用户

发布于 2009-10-29 09:54:57

我没有注意到,也没有看到任何提到addDependency:的地方,这似乎是让操作按正确顺序执行的先决条件。

简而言之,第二个操作取决于第一个操作。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/1642444

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档