Question

I am trying to get a busy view displayed during a search process however it never seems to display.

What I am trying to achieve

  1. User clicks on search button once they have entered the text in a UISearchBar.
  2. The text entered is delegated to searchBarSearchButtonClicked.
  3. Show a "Busy view" which is a UIView containing a UIActivityIndicatorView to indicate the search is underway.
  4. Perform a search which communicates with a website.
  5. On search completion remove the "Busy View".

Whats wrong

The search process is working fine, using the debugger I can see it moving through the searchBarSearchButtonClicked function fine however the "Busy View" never appears. The search takes 2-3 seconds so in theory I should see my "Busy View" appear for those 2-3 seconds.


Code Attempt 1 - Add and remove the "Busy View" from the superview**

- (void)searchBarSearchButtonClicked:(UISearchBar *)activeSearchBar {

 [activeSearchBar setShowsCancelButton:NO animated:YES];
 [activeSearchBar resignFirstResponder];
 [busyView activateSpinner]; //start the spinner spinning
 [self.view addSubview:busyView]; //show the BusyView

 Search *search = [[Search alloc]init];
 results = [search doSearch:activeSearchBar.text];

 [busyView deactivateSpinner]; //Stop the spinner spinning
 [busyView removeFromSuperview]; //remove the BusyView
 [search release]; search = nil;

}

Results Of Attempt 1 - It does not appear, however if I comment out the removeFromSuperview call the Busy View remains on screen.


Code Attempt 2 - using animations

- (void)searchBarSearchButtonClicked:(UISearchBar *)activeSearchBar {



[activeSearchBar setShowsCancelButton:NO animated:YES]; 
 [activeSearchBar resignFirstResponder];

 [UIView beginAnimations:nil context:nil];
 [UIView setAnimationDuration:0];
 [UIView setAnimationDelegate:self];
 [UIView setAnimationDidStopSelector:@selector(animationDidStop)];

 [busyView activateSpinner]; //start spinning the spinner
 [self.view addSubview:busyView]; //show the busy view

 [UIView commitAnimations];

 Search *search = [[Search alloc]init];
 results = [search doSearch:activeSearchBar.text];


 [UIView beginAnimations:nil context:nil];
 [UIView setAnimationDuration:0];
 [UIView setAnimationDelegate:self];
 [UIView setAnimationDidStopSelector:@selector(animationDidStop)];

 [busyView deactivateSpinner]; //sets stops the spinner spinning
 [busyView removeFromSuperview]; //remove the view

 [UIView commitAnimations];
 [search release]; search = nil;
}

Results of attempt 2 - Did not see the "Busy View" appear

Was it helpful?

Solution

Well, Here's my solution:

  • Create singleton class MyLoadingView. This class should contain show and hide static methods.
  • In MyLoadingView constructor you should manually create a view with semi-transparent black background and activityview inside of it. Place this view into [[UIApplication sharedApplication] keyWindow]. Hide it.
  • [MyLoadingView show] invocation just brings myLoadingView object to front in it's container: [[[UIApplication sharedApplication] keyWindow] bringSubviewToFront:myLoadingViewSharedInstance];. Also don't forget to start activityview animation.
  • [MyLoadingView hide] stops activityview animation and hides sharedInstanceView.

Please notice, that you need to invoke [MyLoadingView show] in a separate thread.

OTHER TIPS

UI changes in Cocoa only take effect the next time your code returns control to the run loop. As long as your search task runs synchronously on the main thread, it will block execution, including UI updates.

You should execute the time-consuming task asynchronously in the background. There are a number of options for this (NSOperation, performSelectorInBackground:..., Grand Central Dispatch, ...).

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top