ios - 使用dispatch_semaphore时执行dispatch_after

标签 ios objective-c-blocks grand-central-dispatch

当我想在我的dispatch_after block 中执行代码时遇到问题。
首先,当按下按钮时我调用 UIActivityIndi​​cator 以便在屏幕上显示它,并且在 uiactivityindicator 开始运行后我想执行服务器调用,当我从服务器收到响应时我返回该值。< br/>
问题是:当我调用 UIAtivityIndi​​cator 来运行并且之后进行服务器调用时,即使调用 [UIActivityIndi​​catorInstance startAnimating]; ,UIActivityIndi​​cator 也不会显示在屏幕中,之后服务器操作被调用。
所以我决定使用 dispatch_after 以便在 de [UIActivityIndi​​catorInstance startAnimating]; 之后等待一段时间,当我这样做时,问题就变成了我必须返回值,因此因此使用 dispatch_semaphore 告诉我操作何时完成,然后返回值。

这里的大问题是没有调用dispatch_after。 这是我的代码,我很感激您可以帮助我解决这个问题或您想到的其他解决方案。
我想要实现的主要想法是,我想在服务器操作执行时显示 UIActivityIndi​​cator,并且当它完成时,我想以相同的方法返回该值。


- (BOOL)getUserSatatus {
     // This is when the UIActivityIndicator is starts running
     [Tools startActivityIndicator];
     double delayInSeconds = 0.5;
     // This is used to save server response.
     __block BOOL serverResponse;

     dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
     dispatch_time_t executionTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC);
     // I want to execute the server call after a perios of time in order to show first de indicator on screen
     dispatch_after(executionTime, dispatch_get_main_queue(), ^{
         NSLog(@"This is where the server will call");
         // This is when I perform the service call and it returns a values that is
         // assigned to server response.
         serverResponse = [_backendManager getStatus];
         // This is the signal for the semaphore in order to execute the next lines.
         dispatch_semaphore_signal(semaphore);
    });

    // Wait until the signal in order to execute the next line.
    dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
    return serverResponse; // Here will be the server return response.
}

最佳答案

你说:

The big problem here is that the dispatch_after is not called.

是的,那是因为您使用 dispatch_semaphore_wait 阻塞了主线程,因此 dispatch_after 永远没有机会在主线程上运行,并且您陷入了死锁。

我们可以引导您解决这个问题,但您确实不应该在代码中使用同步网络调用或信号量(出于多种原因,不仅仅是为了您的事件指示器和解决死锁问题)。

您应该删除这些同步网络请求,删除dispatch_after,并删除信号量。如果您执行所有这些操作,并遵循异步模式(例如使用完成 block ),那么您的事件指示器 View 内容将正常工作,并且也不会有任何死锁。

正确的答案是重构“后端管理器”以异步执行其请求(使用完成 block ),然后也将完成 block 模式与 getUserStatus 方法一起使用。

例如,假设您将 _backendManagergetStatus 修复为异步行为:

- (void)getStatusWithCompletion:(void (^)(BOOL))completion {
    NSMutableURLRequest *request = ...   // build the request however appropriate
    NSURLSessionTask *task = [[NSURLSession sharedSession] dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
        BOOL status = ...;   // parse the response however appropriate
        dispatch_async(dispatch_get_main_queue(), ^{
            if (completion) completion(status);
        });
    }];
    [task resume];
}

然后您可以重构问题中的 getUserStatus 以获取完成处理程序:

- (void)getUserStatusWithCompletion:(void (^)(BOOL))completion {
    // This is when the UIActivityIndicator is starts running
    [Tools startActivityIndicator];

    [_backendManager getStatusWithCompletion:^(BOOL status){
        [Tools stopActivityIndicator];
        if (completion) completion(status);
    }
}

然后需要获取用户状态的代码将执行以下操作:

[obj getUserStatusWithCompletion:^(BOOL success) {
    // use `success` here
}];

// but not here

关于ios - 使用dispatch_semaphore时执行dispatch_after,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33326220/

相关文章:

ios - Swift 3.0 无法将 (_, _)->() 类型的值转换为预期参数类型 'ObjectsOrErrorBlock'

ios - NSHTTPURLResponse 为 nil 但未生成 NSError

ios - 未调用dispatch_async block

ios - View 不在屏幕时的 UIView 动画 alpha 不起作用

ios - popoverPresentationControllerDidDismissPopover 的替代方法?

ios - 在完成 block 中访问 super 的正确方法

objective-c - 复制 block - 复制原始类型的捕获变量

ios - 序列化 NSURLConnection 请求 (iOS) - 使用同步请求?

swift - 为什么我的 DispatchGroup 的等待总是超时?

ios - Xcode 不显示build设置选项的菜单