dispatch_semaphore_wait不等待信号量

时间:2014-08-27 13:37:05

标签: ios objective-c iphone semaphore

我开发了以下方法,它检查应用程序与服务器通信的能力。 该方法执行一个简单的查询,并知道如果它得到一个结果,应该连接应用程序(基本的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;
}

我正在使用Apple documentation

中建议的'dispatch_semaphore_wait'

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

使用上面的代码,'dispatch_semaphore_wait'永远不会实际等待,即执行不会在该行停止,而是立即继续(总是将49返回到dispatch_semaphore_wait调用)。这是除非我使用DISPATCH_TIME_FOREVER,在这种情况下应用程序永远挂起......

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

可能导致此行为的原因是什么? 感谢。

3 个答案:

答案 0 :(得分:11)

dispatch_semaphore_wait的参数不是延迟,而是信号量应该唤醒的时间。 1月1日午夜过后,您将醒来30秒。 1970年(或2001年,不确定)。使用dispatch_time函数。

答案 1 :(得分:2)

- (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;
}

答案 2 :(得分:1)

首先,如果在主线程上调用了failcomplete块,那么您将永远等待,或者直到您指定的超时时间超过&#39; < / p>

原因是因为主线程在您致电dispatch_semaphore_wait后开始等待。然后,如果你的performSOQLQuery调用主线程上的块,那么在超时&#39;超时之前不会发生任何事情。

如果你指定一个永远的时间,那么现在很粗糙,信号量将永远不会发出信号或松开,这意味着你的主线程将永远等待它自己。

将等待代码更改为:永远不要让主线程等待

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()方法不在主线程上。