dispatch_semaphore_wait不等待信号量



我开发了以下方法,用于检查应用程序与服务器的通信能力。该方法执行一个简单的查询,并知道如果得到结果,应用程序应该被连接(基本的ping机制)。

- (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"

我的目标是等待响应或短暂的超时,以确定我们是否真的有一个有效的连接。

在上面的代码中,"dispatch_semaphore_wait"实际上从不等待,即执行不会在那一行停止,而是立即继续(总是返回49作为dispatch_semaphore_waite调用的结果)。除非我使用DISPATCH_TIME_FOREVER,否则应用程序将永远挂起。。。

目前,我正在从主线程调用此方法。我知道这是一个坏主意,但我希望在重构之前看到它按预期工作。

是什么导致了这种行为?谢谢

dispatch_semaphore_wait的参数不是延迟,而是信号量应该唤醒的时间。你的将在1月1日午夜后30秒醒来。1970年(或2001年,不确定)。使用dispatch_time函数。
- (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;
}

首先,如果您的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);
});

并且不要像您正在做的那样返回Bool,因为这是一个漫长的操作,您希望使用一个有结果的块。

还要确保performSOQLQuery()方法不在主线程上。

最新更新