IOS multithreading - how to make a thread wait for a state?

I am creating an application that retrieves a result set from a database - I use MBProgressHUD to show the progress of the query with animation. The method I use calls the animation when the method runs on another thread, and after that it hides the animation. My question, after the call:

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

I would like, if there are no results, to display a warning that states this, and if so, download the following view. So far I have this code:

 [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]; } 

self.thereAreEvents set at the end of the getResults method. However, since this method is called on another thread, this execution line continues and displays a warning, even if there are events in the database.

So, I have two questions: what is the easiest way to implement the wait mechanism in iOS and what is the most efficient way to implement this mechanism in iOS?

Thanks!

+6
source share
5 answers

You can also consider NSConditionLock .

So this will be something like this in thread 1:

 [conditionLock lockWhenCondition:kConditionOkayToProceed]; [conditionLock unlockWithCondition:kConditionGettingResults]; [HUD show...] [conditionLock lockWhenCondition:kConditionResultsFetched]; [conditionLock unlockWithCondition:kConditionOkayToProceed]; 

And in the HUD:

 - (void)show... { [conditionLock lockWhenCondition:kConditionGettingResults]; // stuff here [conditionLock unlockWithCondition:kConditionResultsFetched]; } 

Although a much better solution would be to pass the block or target / selector to the HUD, which it should execute when receiving the results.

EDIT: so you get code like:

 [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]; } }]; 

And in the HUD:

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

With an HUD with extra intelligence, to take dispatch_block_t as the last argument and call it when the results are (regardless of whether sending back to the main thread is guaranteed or otherwise).

+2
source

You can use the busy wait loop for a quick and dirty solution:

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

In "real" code, it is better to use a semaphore:

 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); 

This is better than a busy cycle because a blocked thread does not consume CPU time.

The best solution is not to block and reverse engineer your code to work asynchronously. In your case, you should display a counter and start downloading data. When the data is complete, you should receive an asynchronous callback (either through a block or a goal / action callback), and display the results, or show an error message. In this case, locking with an employment cycle or semaphore is a solution for the poor.

+11
source

Not sure if this is the best way to do this, but I will try to use a while loop to observe some booleans with something like [NSThread sleepForTimeInterval: 1]; inside the loop.

It is also possible to set a timeout.

0
source

This is your way: Concurrency Programming Guide

Also: Sync

More sharp: Using locks . I think the latter could help.

Another simple approach is bad but works

 NSAssert(![NSThread isMainThread], @"Do not run on MAIN thread"); while (yourCondition) { [NSThread sleepForTimeInterval:0.2]; } 
0
source

you can use dispatch_time_t as ..

 double delayInSeconds = 2.0; dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC)); dispatch_after(popTime, dispatch_get_main_queue(), ^(void){ <#code to be executed on the main queue after delay#> }); 
0
source

Source: https://habr.com/ru/post/910103/


All Articles