2011-11-20 97 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,@「我們不想被暫停。」); –