iOS中的多线程 - 如何强制线程等待条件?

Ker*_*rrM 6 iphone multithreading cocoa-touch ios

我正在创建一个从数据库中获取一组结果的应用程序 - 我使用MBProgressHUD来显示带动画的查询进度.我使用的方法在另一个线程中执行方法时调用动画,一旦完成,它就会隐藏动画.我的问题是,在致电:

[HUD showWhileExecuting:@selector(getResults) onTarget:self withObject:nil animated:YES];
Run Code Online (Sandbox Code Playgroud)

我想,如果没有结果,则显示一条警告,说明这一点,如果有,则加载下一个视图.到目前为止,我有这个代码:

[HUD showWhileExecuting:@selector(getResults) onTarget:self withObject:nil animated:YES];

if(self.thereAreEvents) {
    [self performSegueWithIdentifier:@"searchResults" sender:self];
} else {
    UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"No results" message:@"Sorry, there are no results for your search. Please try again." delegate:self cancelButtonTitle:@"OK" otherButtonTitles:nil, nil];
    [alert show];
    [alert release];
}
Run Code Online (Sandbox Code Playgroud)

self.thereAreEventsgetResults方法结束时设置.但是,由于该方法在另一个线程中被调用,因此即使数据库中存在事件,该执行行也会继续并显示警报.

所以,从这里开始,我有两个问题:在iOS中实现等待信号机制的最简单方法是什么?在iOS中实现这种机制的最有效方法是什么?

谢谢!

zou*_*oul 11

您可以使用忙等待循环来获得快速而肮脏的解决方案:

__block BOOL finished = NO;
dispatch_async(/* global queue */, ^{
    // …
    finished = YES;
});
while (!finished) /* waiting */;
Run Code Online (Sandbox Code Playgroud)

在"真实"代码中,最好使用信号量:

dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
dispatch_async(/* global queue */, ^{
    // …
    dispatch_semaphore_signal(semaphore);
});
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
dispatch_release(sempahore);
Run Code Online (Sandbox Code Playgroud)

这比busy循环更好,因为被阻塞的线程不占用CPU时间.

最好的解决方案是防止阻塞和重新设计代码以异步工作.在您的情况下,您应该显示一个微调器并开始下载数据.数据下载完成后,您应该收到异步回调(通过块或目标/操作回调)并显示结果或显示错误警报.在这种情况下,使用繁忙的循环或信号量阻塞是一个穷人的解决方案.


Tom*_*mmy 2

您还可以考虑一个NSConditionLock.

所以线程 1 上会是这样的:

[conditionLock lockWhenCondition:kConditionOkayToProceed];
[conditionLock unlockWithCondition:kConditionGettingResults];

[HUD show...]

[conditionLock lockWhenCondition:kConditionResultsFetched];
[conditionLock unlockWithCondition:kConditionOkayToProceed];
Run Code Online (Sandbox Code Playgroud)

在平视显示器中:

- (void)show...
{
    [conditionLock lockWhenCondition:kConditionGettingResults];

    // stuff here

    [conditionLock unlockWithCondition:kConditionResultsFetched];
}
Run Code Online (Sandbox Code Playgroud)

尽管更好的解决方案是将块或目标/选择器传递给 HUD,HUD 将在获取结果时执行该操作。

编辑:所以你最终会得到如下代码:

[HUD showWhileExecuting:@selector(getResults)
     onTarget:self
     withObject:nil
     animated:YES
     performWhenFinished:
     ^{
         if(self.thereAreEvents) {
             [self performSegueWithIdentifier:@"searchResults" sender:self];
         } else {
             UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"No results" message:@"Sorry, there are no results for your search. Please try again." delegate:self cancelButtonTitle:@"OK" otherButtonTitles:nil, nil];
             [alert show];
             [alert release];
         }
      }];
Run Code Online (Sandbox Code Playgroud)

在平视显示器中:

- (void)showWhile... performWhenFinished:(dispatch_block_t)block
{
     // all the other stuff you were going to do here, then
     // eventually...

     // if no guarantees, maybe just:
     block();

     // otherwise, if promised to dispatch to the main queue:
     dispatch_async(dispatch_get_main_queue(), block);
}
Run Code Online (Sandbox Code Playgroud)

HUD 具有额外的智能,可以将 adispatch_block_t作为最终参数,并在结果出现时调用它(无论是否保证分派回主线程或以其他方式)。