UIActivityIndicatorView does not spin immediately - ios

I'm facing a strange issue about the animation of the UIActivityIndicatorView.
I have a splitViewController where I have a UITableView on the left side, and another one on the right side.
When I enter the application I am doing some operations in background to load datas and each UITableViewCell of the tables will contains a UIActivityIndicatorView.
The operations that have to be executed on the left side are on a queue. The operations to execute on the right side are on a different queue.
The right side operations have major priority respect the operations that have to be executed on the left side.
When the right side queue start, The UIActivityIndicatorView is placed in each UITableViewCell of the table and starts immediately.
When the left side queue start, The UIActivityIndicatorView is placed in each UITableViewCell of the table but does not start the animation immediately. (I have to scroll the table to force the animation).
How can I solve this situation?
How can I animate the UIActivityIndicatorView on the other table without having to scroll the table?

I don't know what kind of thread you use to run operation in background but if effect to interface (UIActivityIndicatorView in your situation) my recommendation for you is using the following code to Run UI and load operation thread
dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void){
//Background Thread
dispatch_async(dispatch_get_main_queue(), ^(void){
//Run UI Updates
});
});

Related

Scroll and add Search Bar asynchronously

I have this application in which I have a right bar button item which adds the search bar as title view. This works fine but when the table view is scrolling, this doesn't happen. It only adds when the table view has stopped scrolling.
Any way to handle this?
The main thread does not responds to events if its busy, use GCD to add this to Queue
Check if this function is called while scrolling. If yes , then simply using GCD will solve your problem.
-(void)userTapOnRightBarButton{
NSLog(#"Main thread response to touch during scrolling"):
dispatch_async(dispatch_get_main_queue(), ^{
[self addSearchBar];
});
}

Objective c- Show Loading Screen before main thread gets blocked completely

In my app I have two methods to hide and show a subview of a view controller called
-(void)hideCurrentView
-(void)showCurrentView
They are always called together. When calling hideCurrentView I want to start showing a loading screen and then hide this loading screen when showCurrentView has shown all necessary ui elements. My loading screen is a view with an activity indicator as a subview. The problem is that I have to do all the actions that happen in hideCurrentView and showCurrentView on the main thread. That is why my loading screen will never show up. :-(
I tried to put the show loading screen method to a background thread:
-(void)hideCurrentView {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, (unsigned long)NULL), ^(void) {
[self showLoadingScreen];
});
[self performSelectorOnMainThread:#selector(hideCurrentViewOnMainThread) withObject:nil waitUntilDone:YES];
}
-(void)showCurrentView {
[self performSelectorOnMainThread:#selector(showCurrentViewOnMainThread) withObject:nil waitUntilDone:YES];
}
That does not work. The loading screen never shows up because the main thread is blocked. I also tried showing the loading screen directly on the main thread but it doesn´t work too.
Can anyone tell me hoew to show the loading screen before doing the ui actions and then hide it again when all ui actions have finished?
Thanks for your help!
You should not call showLoadingScreen in a background thread if you are just adding a subview. (or more generally manipulating the UI)
I'm guessing you have something in your hideCurrentViewOnMainThread that is not UI related and blocks the main thread and it's that part of the code that should be run in another thread.

ios activity indicator is visible once, and then will not show until I try again a minute later

Ok, so I have this piece of code:
- (void) searchBarSearchButtonClicked:(UISearchBar *)aSearchBar
{
[_activity startAnimating];
[self.searchBar bringSubviewToFront:_activity];
[self.searchBar resignFirstResponder];
if([_activity isAnimating]){
NSLog(#"its animating!");
}
dispatch_queue_t background = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0);
dispatch_async(background, ^{
[self performSelectorOnMainThread:#selector(filter:) withObject:aSearchBar.text waitUntilDone:YES];
dispatch_async(dispatch_get_main_queue(), ^{
[_activity stopAnimating];
if(![_activity isAnimating]){
NSLog(#"its not animating anymore!");
}
[self.tableView reloadData];
});
});
}
what i'm trying to do is start an activity indicator which I added as a subview to the search bar. In this code, I start the animation (logging for test) on the main thread, then set up a background asynchronous thread which runs the method that generates the new data set which will reload the tableview. I wait for this to return, and which point, I stop animation and reload the tableview on the main thread.
the result is this...when the application runs, I go to the table view, and I type a word in the search bar. When I hit enter, the activity indicator shows up, the table loads, and the activity indicator stops. This is great.
Then, I click on the search bar again, start a new search, only this time, the activity indicator does not show itself, but the NSLog shows that it IS animating. The tableview reloads as expected, but no activity indicator on the UI, but based on the NSLog, it seems to working.
Finally, if I wait about a minute, and search again, it works fine. What I'm suspecting is that that the background thread is not completing maybe, and the main thread continues doing what it needs to do.
Honestly, I've been beating my head for two days now, can someone explain what I'm doing wrong?
There's a chance that this has something to do with the view hierarchy, depending on where you added the UIActivityIndicatorView to. If you added it directly to the search bar, it might reorganize the subviews in a way you don't expect (and move the activity indicator behind some of them, blocking it from being visible, even though it's animating.)
A good option might be to embed the search bar within a toolbar, and then have the activity indicator on the left (or right) with flexible space separating it from the search bar.

App stops receiving NSTimer selector callbacks during any UI scrolling operation

I have an OpenGL animation drawing on the main window fired by an NSTimer. If I bring up a popover window with a scrollable UITableView menu, the animation freezes while scrolling is in process. Once the scrolling animation stops, the timer callbacks start again. Its only when the user actively tries to scroll that the main window stops updating.
It seems like Apple's scroll animation is somehow blocking dispatch on the main loop. Is this true and is there a way to fix it?
I dont really want to introduce multithreading if I can help it because that will exponentially increase the complexity of my code.
Also I tried using CADisplayLink instead of NSTimer and the display link calls are also blocked by the scrolling animation.
As answered by bdesham, "Apple’s #1 priority is UI responsiveness, and so in situations like this, UI actions will block other parts of your code. You need to move your timer to another thread."
NSTimer are tied to a run loop and mode. During event tracking, the mode is UITrackingRunLoopMode. By default, timers created by scheduledTimerWithTimeInterval are added with NSDefaultRunLoopMode and so do not fire during tracking.
[[NSRunLoop currentRunLoop] addTimer:yourTimer forMode:UITrackingRunLoopMode];

iOS: Presenting a spinning wheel while NSFetchResultsController is performing a fetch

I am using a NSFetchedResultsController to populate a UITableView. The fetch take some time so I would like to present a spinning wheel to the user while the fetch is under way.
How would I do that?
You should start your spinner in the Main thread and push the "heavy work" for a secondary thread. When the work is done, stop the spinner. You can achieve that with something like this:
// Start the spinning here.
[mySpinner startAnimating];
// Declare the queue
dispatch_queue_t workingQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
// it's not, so we will start a background process to calculate it and not block the UI
dispatch_async(workingQueue,
^{
// Some heavy work here.
dispatch_async(dispatch_get_main_queue(), ^{
// stop the spinner here
[mySpinner stopAnimating];
});
});
Doing the following in the Main thread wont make you accomplish what you want:
Start Spinner => Heavy work => Stop Spinner
When the Heavy work begins, it will block your UI thread, so you won't actually see the UIActivityMonitor animating.
To finish I would advise you using this as spinner.
You have several way to do that :
had a UIBarItem if you use UINavigationBar and set customView to UIActivityIndicator at the beginning of your function and hide it a the end.
Create a "modal" view with a UIActivityIndicator at the center of the view, and add this subview to your table view and remove it a the end of your function.
formally just you can use the UIActivityIndicatorView to present the wheel and for some good and delicate way use the MBHoods from here download the demo app here

Resources