首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用dispatch_after时执行dispatch_semaphore

使用dispatch_after时执行dispatch_semaphore
EN

Stack Overflow用户
提问于 2015-10-25 04:33:14
回答 1查看 406关注 0票数 2

当我想在dispatch_after块中执行一段代码时,我遇到了问题。

首先,当按下按钮以便在屏幕上显示它时,我正在调用一个UIActivityIndicator,在uiactivity指示器开始运行之后,我想要执行一个服务器调用,当我从服务器得到响应时,返回这个值。

问题是:当我调用我的UIAtivityIndicator来运行,然后进行服务器调用时,即使在调用[UIActivityIndicatorInstance startAnimating];和调用服务器操作之后,[UIActivityIndicatorInstance startAnimating];也不会在屏幕上显示。

因此,我决定使用dispatch_after,以便在de [UIActivityIndicatorInstance startAnimating];之后等待一段时间,当我这样做时,问题就变成了当我必须返回值时,因此使用dispatch_semaphore来告诉我操作什么时候完成,然后返回值。

这里的大问题是dispatch_after没有被调用。这是我的代码,我很感谢你能帮我解决这个问题或者你想要的其他解决方案。

我想要实现的主要思想是,在服务器操作执行时显示一个UIActivityIndicator,当它完成时,我希望在相同的方法中返回该值。

代码语言:javascript
复制
- (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.
}
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2015-10-25 05:52:16

你说:

这里的大问题是dispatch_after没有被调用。

是的,这是因为您用dispatch_semaphore_wait阻塞了主线程,所以dispatch_after从来没有机会在主线程上运行,而且是死锁的。

我们可以向您介绍解决这些问题的方法,但是您确实不应该在代码中使用同步网络调用或信号量(原因很多,不仅仅是因为您的活动指示器和解决您的死锁问题)。

您应该删除这些同步网络请求,删除dispatch_after,并删除信号量。如果您这样做,并且遵循异步模式(比如使用完成块),那么您的活动指示器视图就会正常工作,您也不会有任何死锁。

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

例如,假设您修复了_backendManager_backendManager以异步运行:

代码语言:javascript
复制
- (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,以接受一个完成处理程序:

代码语言:javascript
复制
- (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);
    }
}

然后,需要获得用户状态的代码将执行如下操作:

代码语言:javascript
复制
[obj getUserStatusWithCompletion:^(BOOL success) {
    // use `success` here
}];

// but not here
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/33326220

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档