2012-03-22 27 views
1

我發現這個線程作爲參考:How do I wait for an asynchronously dispatched block to finish?和我正在使用該代碼(發信號塊內的信號量)等待我的線程完成測試之前完成。信號量從未在單元測試信號(dispatch_get_main_que()從來沒有運行?)

但是我從來沒有信號燈的信號,它的做...所以我通過代碼加強,發現這個小片段中的代碼永遠不會運行:

 dispatch_async(dispatch_get_main_queue(), ^{ 
      [self removeDownloadSpinner]; 
      block(callback); 
     }); 

是否dispatch_get_main_queue()不是當我單位解僱測試?如果不是,你如何單元測試異步塊?

編輯(這裏是更多的代碼): 基本上我有一個「ServerRequest」類,其中包含所有應用程序的傳入/傳出網絡請求。一種方法是這樣(完成塊typedeffed):

+(void)checkPlayerCode:(NSString *)playerCode completionHandler:(PlayerCompletionBlock)block { 
    [self addDownloadSpinner]; 
    NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:@"%@/players/%@",kBaseURL, playerCode]]; 
    NSURLRequest *request = [[NSURLRequest alloc] initWithURL:url]; 
    [ServerConnectionRequest sendAsynchronousRequest:request queue:[[NSOperationQueue alloc] init] completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) { 
    NSDictionary *p = [data objectFromJSONData]; 
    Player *player = [[Player alloc] init]; 
    player.last_name = [p objectForKey:@"last_name"]; 
    if (!error) { 
     dispatch_async(dispatch_get_main_queue(), ^{ 
      [self removeDownloadSpinner]; 
      block(player); 
     }); 

    } 
}]; 

}

這是從一個UIViewController稱爲像這樣:

[ServerRequest checkPlayerCode:codeCell.textField.text completionHandler:^(Player *p){ 
    UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"wooo block" message:@"works" delegate:nil cancelButtonTitle:@"Ok" otherButtonTitles: nil]; 
    [alert show]; 
}]; 

然而dispatch_get_main_queue()塊永遠不會被解僱。

回答

1

的問題是,你正在等待信號燈的主線程,同時試圖與dispatch_async主胎面執行一些代碼(dispatch_get_main_queue( ),...)。 嘗試使用NSRunLoop的runUntilDate,像

__block volatile bool loadComplete = false; 
dispatch_async(dispatch_get_main_queue(), ^(..) 
               {                  
                .. 
                loadComplete = true; 
               }); 

NSDate* startTime = [NSDate date]; 
while (!loadComplete) 
{ 
    NSDate* nextTry = [NSDate dateWithTimeIntervalSinceNow:0.1]; 
    [[NSRunLoop currentRunLoop] runUntilDate:nextTry]; 

    if ([nextTry timeIntervalSinceDate:startTime] > ../* some appropriate time interval here */) 
     STAssertTrue(false, @"TIMEOUT"); 
} 

// Assertions here 
1

在單元測試中執行多線程代碼沒有問題,我已經在其中運行了各種各樣的調度代碼。

當你說穿過代碼時,你的意思是說你逐字地使用調試器。如果是這樣,並且你認爲代碼沒有運行,因爲調試器沒有停在塊中,那麼你必須記住這將在另一個線程上運行,並且你需要一個斷點來停止它。

所以我會在塊內分配斷點。

其次,如果您測試的代碼是從主線程運行,那麼這將無法正常工作,因爲您無法在您所在的同一線程上執行某些代碼。單元測試代碼應該在後臺線程上運行。

然後是執行時間問題。因爲你正在運行一個異步塊,它可能只是它尚未執行。

異步調用的測試意味着上面的代碼可能需要等待異步調用完成才能聲明它可能已經完成的任何事情。在這種情況下,您必須考慮它應該是同步而不是異步。

你需要表現出更多的代碼,我想:-)

+0

所以我在實際塊更多的代碼添加。是的,我的意思是我逐字逐句通過調試器。後臺線程關閉......但回調塊內部的中斷不會被觸發。也認爲這個問題可能是測試在主線程上運行;然而,我只是試圖在後臺線程上運行測試(gcd priority default),它仍然無法正常工作。我是否應該發佈我的測試? – Msencenb 2012-03-23 09:44:36

+0

想我越來越近了。問題在於我的信號量鎖定了主線程,所以其他回調無法獲得線程。但是,如果我將semaphore_wait調用移入異步線程,則單元測試不會等待並完成。任何機會你可以給我一個單元測試的例子,它使用信號量等待而不阻塞主線程? – Msencenb 2012-03-23 09:52:12

+0

對我沒有任何幫助。幾周前我做了一些信號量的代碼,然後重構了它。但正如你所說,你必須小心鎖定你正在執行的線程。正如我最近向其他人建議的那樣,請看看GCD和運營。對於您正在嘗試解決的較大問題,這可能是一個更容易,更好的答案。 – drekka 2012-03-23 13:41:59