Scroll and add Search Bar asynchronously - ios

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

Related

Smooth UITableView scrolling while calling reloadData

Im using a method to get new item from web after user scrolls end of my UITableView.
when user hit end of list im calling my fetching class inside :
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0)
to avoid ui freeze and get,parse new item from Serve r.
there is no lag here , but when i try reload data inside my table and adding item to
list (reladData) there is a minor hiccup is scrolling. its about 0.4 or 0.5 second and also
scrolling will be freezed during this time.
i even tried to use this method :
dispatch_async(dispatch_get_main_queue(), ^(void)
{
[self.tableView performSelectorOnMainThread:#selector(reloadData) withObject:nil waitUntilDone:YES]
instead of normal reloadData but lag still apear.
is there anyway to avoid this , or should i create Message/progress animation or something
else to notify user during this lag like "please wait" pop up?

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.

Avoid table view didSelectRowIndexPath action while main thread is blocked

I have a problem. In my app action sheet with picker opens when table's row tapped.
My problem is that action sheet dose not opens while main thread is blocked but touch event are added in run loop therefore, whenever main thread gets a change it completes all touches action as a result action sheet opens according to the number of times we tapped on table row. But I want this only once.
How to fix this problem???
The main thread should never be "blocked"... Try running whatever is "blocking" the main thread on a different thread by doing the following.
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[self doSomeLongTask]; // 1
dispatch_async(dispatch_get_main_queue(), ^{
[self longTaskDidFinish]; // 2
});
});

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