使用 dispatch_semaphore 时执行 dispatch_after
Executes dispatch_after when using dispatch_semaphore
当我想在 dispatch_after 块中执行代码时遇到问题。
首先,我在按下按钮时调用 UIActivityIndicator 以便在屏幕上显示它,并且在 uiactivityindicator 启动后 运行nning 我想执行服务器调用,当我从服务器收到响应时我return那个值。
问题是:当我将 UIAtivityIndicator 调用到 运行 之后调用服务器时,UIActivityIndicator 不会显示在屏幕上,即使调用了 [UIActivityIndicatorInstance startAnimating];
之后调用了服务器操作.
所以我决定使用 dispatch_after
以便在 de [UIActivityIndicatorInstance startAnimating];
之后等待一段时间它在我这样做时有效,当我必须 return 值时,问题就来了,所以为此原因是使用 dispatch_semaphore
告诉我操作何时完成,然后 return 值。
这里的大问题是 dispatch_after
没有被调用。
这是我的代码,感谢您能帮助我解决这个问题或您想到的其他解决方案。
我想要完成的主要想法是我想在服务器操作执行时显示一个 UIActivityIndicator,当它完成时我想 return 在相同的方法中那个值。
- (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
永远没有机会在主线程上 运行 并且你陷入了僵局。
我们可以指导您解决这个问题,但您真的根本不应该在代码中使用同步网络调用或信号量(出于多种原因,不仅仅是因为您的 activity 指标并解决您的僵局问题)。
您应该删除这些同步网络请求,删除 dispatch_after
,并删除信号量。如果你做所有这些,而不是遵循异步模式(比如使用完成块),你的 activity 指示器视图将正常工作,你也不会有任何死锁。
正确答案是重构 "back end manager" 以异步执行其请求(使用完成块),然后也使用带有 getUserStatus
方法的完成块模式。
例如,假设您修复了 _backendManager
的 getStatus
以异步运行:
- (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
当我想在 dispatch_after 块中执行代码时遇到问题。
首先,我在按下按钮时调用 UIActivityIndicator 以便在屏幕上显示它,并且在 uiactivityindicator 启动后 运行nning 我想执行服务器调用,当我从服务器收到响应时我return那个值。
问题是:当我将 UIAtivityIndicator 调用到 运行 之后调用服务器时,UIActivityIndicator 不会显示在屏幕上,即使调用了 [UIActivityIndicatorInstance startAnimating];
之后调用了服务器操作.
所以我决定使用 dispatch_after
以便在 de [UIActivityIndicatorInstance startAnimating];
之后等待一段时间它在我这样做时有效,当我必须 return 值时,问题就来了,所以为此原因是使用 dispatch_semaphore
告诉我操作何时完成,然后 return 值。
这里的大问题是 dispatch_after
没有被调用。
这是我的代码,感谢您能帮助我解决这个问题或您想到的其他解决方案。
我想要完成的主要想法是我想在服务器操作执行时显示一个 UIActivityIndicator,当它完成时我想 return 在相同的方法中那个值。
- (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
永远没有机会在主线程上 运行 并且你陷入了僵局。
我们可以指导您解决这个问题,但您真的根本不应该在代码中使用同步网络调用或信号量(出于多种原因,不仅仅是因为您的 activity 指标并解决您的僵局问题)。
您应该删除这些同步网络请求,删除 dispatch_after
,并删除信号量。如果你做所有这些,而不是遵循异步模式(比如使用完成块),你的 activity 指示器视图将正常工作,你也不会有任何死锁。
正确答案是重构 "back end manager" 以异步执行其请求(使用完成块),然后也使用带有 getUserStatus
方法的完成块模式。
例如,假设您修复了 _backendManager
的 getStatus
以异步运行:
- (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