2011-11-20 36 views
2

我有一个使用NSOperationQueue的应用程序。NSOperationQueue会随机暂停吗?

有时我注意到,即使我的代码从未调用setSuspended:方法,某些NSOperationQueues会“锁定”或随机进入“isSuspended”状态。

复制并且很难调试是不可能的,因为每当我将设备连接到Xcode进行调试时,应用程序就会重新加载,错误就会消失。

我在所有可能的地方添加了很多NSLogs,可能有问题,只需要使用应用程序几天,直到错误重新出现。查看设备系统日志,我发现[myOperationQueue operationCount]会增加,但队列中的操作将不会执行。

我还没有尝试过手动设置“setSuspended:NO”,但是真的有必要吗?

这可能是什么原因造成的?

这里是我的代码一点点

调用操作

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil 
{ 
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; 
    if (self) { 
     // Custom initialization 
     self.operationQueue = [[[NSOperationQueue alloc] init] autorelease]; 
     [self.operationQueue setMaxConcurrentOperationCount:2]; 

     self.sendOperationQueue = [[[NSOperationQueue alloc] init] autorelease]; 
     [self.sendOperationQueue setMaxConcurrentOperationCount:2]; 

     self.receiveOperationQueue = [[[NSOperationQueue alloc] init] autorelease]; 
     [self.receiveOperationQueue setMaxConcurrentOperationCount:1]; 
    } 
} 

- (void)dealloc 
{ 
    [[NSNotificationCenter defaultCenter] removeObserver:self]; 

    [operationQueue cancelAllOperations]; 
    [sendOperationQueue cancelAllOperations]; 
    [receiveOperationQueue cancelAllOperations]; 

    [operationQueue release]; 
    [sendOperationQueue release]; 
    [receiveOperationQueue release]; 
} 

- (IBAction)sendMessage 
{ 
    if(![chatInput.text isEqualToString:@""]) 
    { 
     NSString *message = self.chatInput.text; 
     SendMessageOperation *sendMessageOperation = [[SendMessageOperation alloc] initWithMatchData:matchData andMessage:message resendWithKey:nil]; 
     [self.sendOperationQueue addOperation:sendMessageOperation]; 
     [sendMessageOperation release]; 
    } 
} 

视图控制器的NSOperation子类SendMessageOperation

- (id)initWithMatchData:(MatchData*)data andMessage:(NSString*)messageString resendWithKey:(NSString*)resendKey 
{ 
self = [super init]; 

    if(self != nil) 
    { 
     if(data == nil || messageString == nil) 
     { 
      [self release]; 
      return nil; 
     } 
     appDelegate = (YongoPalAppDelegate *) [[UIApplication sharedApplication] delegate]; 

     context = [[NSManagedObjectContext alloc] init]; 
     [context setPersistentStoreCoordinator:[appDelegate persistentStoreCoordinator]]; 
     [context setMergePolicy:NSMergeByPropertyObjectTrumpMergePolicy]; 

     [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(mergeContextChanges:) name:NSManagedObjectContextDidSaveNotification object:context]; 

     [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(mergeMainContextChanges:) name:NSManagedObjectContextDidSaveNotification object:appDelegate.managedObjectContext]; 

     self.matchData = (MatchData*)[context objectWithID:[data objectID]]; 
     matchNo = [[matchData valueForKey:@"matchNo"] intValue]; 
     partnerNo = [[matchData valueForKey:@"partnerNo"] intValue]; 

     self.message = messageString; 
     self.key = resendKey; 

     apiRequest = [[APIRequest alloc] init]; 
    } 
    return self; 
} 

- (void)dealloc 
{ 
    [[NSNotificationCenter defaultCenter] removeObserver:self]; 

    self.matchData = nil; 
    self.message = nil; 
    self.key = nil; 
    [context release]; 
    [apiRequest release]; 
    [super dealloc]; 
} 

- (void)start 
{ 
    if([self isCancelled] == YES) 
    { 
     [self willChangeValueForKey:@"isFinished"]; 
     finished = YES; 
     [self didChangeValueForKey:@"isFinished"]; 
     return; 
    } 
    else 
    { 
     [self willChangeValueForKey:@"isExecuting"]; 
     executing = YES; 
     [self main]; 
     [self didChangeValueForKey:@"isExecuting"]; 
    } 
} 

- (void)main 
{ 
    @try 
    { 
     NSAutoreleasePool *pool = [NSAutoreleasePool new]; 

     bool taskIsFinished = NO; 
     while(taskIsFinished == NO && [self isCancelled] == NO) 
     { 
      NSDictionary *requestData = nil; 

      if(key == nil) 
      { 
       requestData = [self sendMessage]; 
      } 
      else 
      { 
       requestData = [self resendMessage]; 
      } 

      NSDictionary *apiResult = nil; 
      if(requestData != nil) 
      { 
       apiResult = [self sendMessageToServer:requestData]; 
      } 

      if(apiResult != nil) 
      {     
       [[NSNotificationCenter defaultCenter] postNotificationName:@"shouldConfirmSentMessage" object:nil userInfo:apiResult]; 
      } 

      taskIsFinished = YES; 
     } 

     [self willChangeValueForKey:@"isFinished"]; 
     [self willChangeValueForKey:@"isExecuting"]; 
     finished = YES; 
     executing = NO; 
     [self didChangeValueForKey:@"isFinished"]; 
     [self didChangeValueForKey:@"isExecuting"]; 

     [pool drain]; 
    } 
    @catch (NSException *e) 
    { 
     NSLog(@"Exception %@", e); 
    } 
} 

- (BOOL)isConcurrent 
{ 
    return YES; 
} 

- (BOOL)isFinished 
{ 
    return finished; 
} 

- (BOOL)isExecuting 
{ 
    return executing; 
} 

- (void)mergeContextChanges:(NSNotification *)notification 
{ 
    [[NSNotificationCenter defaultCenter] postNotificationName:@"mergeChatDataChanges" object:nil userInfo:[notification userInfo]]; 
} 

- (void)mergeMainContextChanges:(NSNotification *)notification 
{ 
    NSSet *updated = [[notification userInfo] objectForKey:NSUpdatedObjectsKey]; 
    for(NSManagedObject *thing in updated) 
    { 
     [[context objectWithID:[thing objectID]] willAccessValueForKey:nil]; 
    } 

    [context mergeChangesFromContextDidSaveNotification:notification]; 
} 
+1

也许不相关,但你给的NSOperation子类不需要并发;你可以避免压倒性的开始,isFinished,isExecuting并让NSOperation为你处理。 –

+0

是的,不知道它是否相关,但谢谢你的提示。 –

回答

-1

看看ASIHTTPRequestConfig.h ,它有一些标志,你可以打开看看什么是真正的hap在幕后进行投票。

+0

是否ASIHTTP调试NSOpeationQueues与ASIHTTP无关? –

+0

它没有,但它肯定会帮助你调试这个问题。 – avicene

+0

我想我可能会误解什么东西,或者也许是另一种方式。但是,虽然我没有提到我在我的问题中使用ASIHTTPRequest,但我正在使用它,而不是ASIHTTPRequest不起作用。这是我的NSOperationQueues和自定义NSOperations没有运行。你能提供一个更明确的答案吗? –

2

您使用:

setMaxConcurrentOperationCount:X 

我的预感是,在队列X作业还没有完成,因此造成任何后续操作添加到队列不运行,直到这种情况。

+0

嗯..现在我想知道。其中一个操作会陷入无限循环或类似的情况吗?这将阻止更多的操作执行。 –

+0

尝试为每个操作分配一个标记或属性来标识它,然后使用NSLog检查“操作1开始/完成” – Alex

0

从NSOperationQueue的isSuspended方法的文档:

如果你想知道什么时候该队列的暂停状态的变化,配置国际志愿者组织观察员观察操作队列的暂停关键路径。

,你可以在与观察者平行执行另一个想法是创建的NSOperationQueue一个子类,它重新定义了setSuspended:方法。在重新定义的版本中,如果您在调试器上运行,则可以设置断点;如果您正在运行无调试器,则可以将堆栈跟踪打印到日志中。

希望这会有所帮助。

+0

只是一个想法,可能会有所帮助:在isSuspended的观察者只是崩溃应用程序并查看堆栈跟踪查看谁在暂停队列。简单的崩溃方式:NSAssert(1 == 0,@“我们不想被暂停。”); –