2014-08-27 111 views
2

我開發了以下方法,它檢查應用程序與服務器通信的能力。 該方法執行一個簡單的查詢,並知道如果它得到一個結果,該應用程序應該連接(基本的ping機制)。dispatch_semaphore_wait不等待信號量

- (BOOL)isAppConnected 
{ 
    __block BOOL isConnected = NO; 

    dispatch_semaphore_t semaphore = dispatch_semaphore_create(0); 

    [[SFRestAPI sharedInstance] performSOQLQuery:@"SELECT id FROM Account LIMIT 1" 
              failBlock:^(NSError *e) { 
               isConnected = NO; 
               NSLog(@"NOT CONNECTED %@", e); 
               NSLog(@"fail block ON THE MAIN THREAD? %hhd", [NSThread isMainThread]); 

               dispatch_semaphore_signal(semaphore); 

              } completeBlock:^(NSDictionary *dict) { 
               isConnected = YES; 
               NSLog(@"%@", dict); 
               NSLog(@"complete block ON THE MAIN THREAD? %hhd", [NSThread isMainThread]); 

               dispatch_semaphore_signal(semaphore); 
              }]; 

    // if the wait times-out we will receive a non-zero result and can assume no connection to SF 
    //When using: DISPATCH_TIME_FOREVER the app hangs forever!! 
    int waitResult = dispatch_semaphore_wait(semaphore, 30 * NSEC_PER_SEC); 
    NSLog(@"waitResult: %d", waitResult); 

    return isConnected; 
} 

我使用的是「dispatch_semaphore_wait」作爲Apple documentation

我的目標是建議等待在響應或短超時弄清楚,如果我們真的有一個有效的連接。

通過上面的代碼,'dispatch_semaphore_wait'永遠不會實際等待,即執行不會在該行停止,但會立即繼續(結果始終返回49,直至dispatch_semaphore_wait調用)。這是除非我使用DISPATCH_TIME_FOREVER在這種情況下,應用程序永遠掛起...

目前我從主線程調用此方法。我意識到這是一個糟糕的主意,但我希望在重構之前按預期工作。

什麼可能導致此行爲? 謝謝。

+0

你從主線程調用它。這就是問題 – 2014-08-27 13:40:17

+0

您是否試過在dispatch_semaphore_signal調用中設置斷點的老式方法?等待執行之前它們是否發信號通知? – gnasher729 2014-08-27 16:21:39

+0

@PetroKorienev是的,確實如此。我在該方法的開始處和回調中添加了一些調試NSLog語句,以打印出它們正在運行的線程。該方法在主線程運行,而回調在不同的線程上執行。我可以猜測,在主線程上執行一個等待會掛起應用程序,但不應該仍然執行回調,並等待wait語句再次釋放執行? – edopuck 2014-08-29 08:43:21

回答

9

dispatch_semaphore_wait的參數不是延遲,而是應該喚醒信號量的時間。你將在1月1日午夜30秒後醒來。 1970年(或2001年,不確定)。使用dispatch_time函數。

+0

謝謝你!我完全誤解了超時的用法。我已經解決了這個問題,但是我認爲我的主要問題與超時設置無關,而是因爲我正在等待主線程?我是這樣說的,因爲當我將超時設置爲DISPATCH_TIME_FOREVER時,這個等待會永久掛起。 – edopuck 2014-08-29 08:46:49

1
- (BOOL)isAppConnected 
{ 
    __block BOOL isConnected = NO; 

    dispatch_semaphore_t semaphore = dispatch_semaphore_create(0); 

    // Add this code... 
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 

     [[SFRestAPI sharedInstance] performSOQLQuery:@"SELECT id FROM Account LIMIT 1" 
              failBlock:^(NSError *e) { 
               isConnected = NO; 
               NSLog(@"NOT CONNECTED %@", e); 
               NSLog(@"fail block ON THE MAIN THREAD? %hhd", [NSThread isMainThread]); 

               dispatch_semaphore_signal(semaphore); 

              } completeBlock:^(NSDictionary *dict) { 
               isConnected = YES; 
               NSLog(@"%@", dict); 
               NSLog(@"complete block ON THE MAIN THREAD? %hhd", [NSThread isMainThread]); 

               dispatch_semaphore_signal(semaphore); 
              }]; 
    }); 

    int waitResult = dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); 
    NSLog(@"waitResult: %d", waitResult); 

    return isConnected; 
} 
1

首先,如果你的failcomplete塊調用在主線程,那麼你會永遠等待,或直到超時指定「超時」

的原因是因爲主線程在您撥打dispatch_semaphore_wait後開始等待。然後如果您的performSOQLQuery調用主線程上的塊,則在超時時間結束之前不會發生任何事情。

現在如果你指定一個永遠的時間,信號量永遠不會發出信號或放開,這意味着你的主線程將永遠等待自己。

更改等待代碼這個:從來沒有讓主線程等待

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{ 
    int waitResult = dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); 
    NSLog(@"waitResult: %d", waitResult); 
}); 

而且不返回一個布爾值,你在做什麼,因爲這是一個冗長的操作,要使用一個塊這有一個結果。

也請確保您的performSOQLQuery()方法不在主線程上。