MBProgressHUD display messages one over the other - iphone

In the viewDidload method, i am using MBProgressHUD to show an activity indicator until data is downloaded from the net, and thereafter to check if the application has enabled GPS. based on this i alert the user using MBProgressHUD.
My code;
ViewDidLoad
hudForDownloadData = [[MBProgressHUD alloc] initWithView:self.navigationController.view];
[self.navigationController.view hudForDownloadData ];
hudForDownloadData .delegate = self;
hudForDownloadData .labelText = #"Loading";
hudForDownloadData .detailsLabelText = #"updating data";
[hudForDownloadData showWhileExecuting:#selector(downloadDataFromWebService) onTarget:self withObject:nil animated:YES];
[self downloadDataFromWebService]; // This method is called, and then data is downloaded from the webservice, once the data is downloaded i will remove the `MBProgressHUD ` alert
Now i am checking if the application has enabled access to GPS, and alert the user if not.
hudForGPS = [[MBProgressHUD alloc] initWithView:self.navigationController.view];
[self.navigationController.view addSubview:HUD];
hudForGPS .delegate = self;
hudForGPS .labelText = #"Loading";
hudForGPS .detailsLabelText = #"updating data";
[hudForGPS showWhileExecuting:#selector(checkIfApplicationEnabledGPS)
onTarget:self withObject:nil animated:YES]; // This will only take a
maximum of 2-3 seconds. and i will remove it after that
The problem is that; when the internet/wifi is down, the hudForDownloadData will continuously animate (display uiactivityindicator). In the meantime hudForGPS will also execute. But it will display below hudForDownloadData . So the user will not be able to see it.
What i want to do is to execute the checkIfApplicationEnabledGPS first, and wait till its alert finishes (it will only take 2-3 seconds), and then load execute the downloadDataFromWebService where if the internet/wifi is not available it will display forever.
How can i do this programatically ?

Execute checkIfApplicationEnabledGPS first and when it is finished,you show an alert box,If you are using UiAlertView to show the alert then you can handle it's delegate:-
-(void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
when the user presses ok button in UiAlert view you can override the above delegate with hudForDownloadData
In this way both the checkIfApplicationEnabledGPS and hudForDownloadData will be executed one after the other

Related

Checking MBProgressHUD status if it hide/show

I'm displaying some views,webVies and while they are loading i display an ProgressHud with waiting message. I'm using an instance of that object :
MBProgressHUD * progrssHUD
Using the show and hide methods to control over loading windows. In some views i would like to add view only after the hide method is turned on - meaning no window displayed now.
How can i check from any interface what is that status of MBProgressHUD and only after status X to do something?
If you see the implementation of MBProgresshud then you will find that when they are hiding it they are setting it's alpha 0 and when they are showing it they are setting it alpha 1.
So you can use this property to check whether it is hidden or shown.
i.e
if(progrssHUD.alpha == 0){
//perform hide operation
}else{
//Perform show operation
}
-(IBAction)SHOW{
HUD = [[MBProgressHUD alloc] initWithView:self.navigationController.view];
[self.navigationController.view addSubview:HUD];
HUD.delegate = self;
[HUD show:YES];
// Show the HUD while the provided method executes in a new thread
[HUD showWhileExecuting:#selector(showHUD) onTarget:self withObject:nil animated:YES];
}
- (void)hudWasHidden:(MBProgressHUD *)hud {
// Remove HUD from screen when the HUD was hidded
[HUD removeFromSuperview];
[HUD release];
HUD = nil;
}
THE METHOD showWhileExecuting CALLING THE HUD WAS ACTIVE WHILE THE DELEGATE METHOD WILL COME.

Objective-c:"Please wait" message when go to the next page

I am developing an app which has several viewControllers. The first one is "MainMenu" and the second one is "Page1".
I would like to show an alert says "Please wait..." when it goes to the next page. My code below is working but the alert comes up after the "page1" is loaded. I would like it to come up when a user press a button on "MainMenu" page.
Do you have any suggestions to accomplish this?
Thanks in advance.
AppDelegate.m
-(void)showAlert{
altpleasewait = [[UIAlertView alloc] initWithTitle:#"Please Wait..." message:nil delegate:self cancelButtonTitle:nil otherButtonTitles: nil];
[altpleasewait show];
UIActivityIndicatorView *indicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge];
indicator.center = CGPointMake(altpleasewait.bounds.size.width / 2, altpleasewait.bounds.size.height - 50);
[indicator startAnimating];
[altpleasewait addSubview:indicator];
}
-(void)waitASecond{
[self performSelector:#selector(dismissAlert) withObject:self afterDelay:0.8];
}
-(void)dismissAlert{
[altpleasewait dismissWithClickedButtonIndex:0 animated:YES];
}
MainMenu.m
-(void)gotoNextPage{
AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication]delegate];
[appDelegate showAlert];
page1 = [self.storyboard instantiateViewControllerWithIdentifier:#"Page1"];
[self presentModalViewController:page1 animated:NO];
}
Page1.m
AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication]delegate];
-------------some methods--------------
[appDelegate waitASecond];
This is just a suggestion. I would do the following.
In Page1.m in -viewDidAppear, I would call the alert view to pop up. This is happening on the main thread. So I am not preventing UI from being displayed, or responsive.
I would move all methods that are related to loading the Page1 content, e.g. texts that are to be read from a URL, into a block, and use GCD, so that they happen in the background, and not blocking the main thread.
Once the loading is done...
I would take them, update the UI, and dismiss the alert view.
Here is a simple tutorial that may give you an idea.
http://www.raywenderlich.com/4295/multithreading-and-grand-central-dispatch-on-ios-for-beginners-tutorial
What you could do is put the alert in the IBAction. Check when they dismiss the alert, then change views. Or use an NSTimer, assign a selector to that timer and implement that selector to change views.

Speed up keyboard dismissing or wait until it's done

I'm having an issue with my save button in a modal UINavController. When I press the save button, I'm dismissing the keyboard if it is still up, validating the data from the text fields, then showing a UIProgressView while I send my info out.
My problem is that the keyboard isn't getting out of the way fast enough, so keyboard is still up when it is time to show the UIProgressView and it is getting added towards the bottom of my view and it looks stupid.
I can hit the return key, and the keyboard drops, then press save, no issues. But if the user skips the keyboard return key and goes right for the top right save button, I have issues.
Ideally I'd like to implement a short wait statement for it to drop out of sight. Or perform my validation after a delay, but nothing I have tried is working. Please help.
Code Example:
// end edit mode - should kill all keyboards
[[self.tableView superview] endEditing:YES];
// make sure everything is entered correctly and validates
[self validateEntryFields]; // keyboard not gone when this finishes
if (valid) { // progress view shows up towards bottom of view
HUD = [[MBProgressHUD alloc] initWithView:self.view];
[self.view addSubview:HUD];
HUD.delegate = self;
HUD.labelText = #"Adding User";
HUD.detailsLabelText = #"Please Wait";
[HUD showWhileExecuting:#selector(sendNewUserInformation) onTarget:self withObject:nil animated:YES];
}
You may use keyboard notification (it would be more correct solution than based on timer):
[notificationCenter addObserver: self selector: #selector(keyboardDidHide:) name: UIKeyboardDidHideNotification object: nil];
And show your progress view in keyboardDidHide: method.
If a small delay would be working you could try the following code between your validation and your if statement where you decide whether or not you will showing the progress view.
You can use the NSTimer object:
[NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:#selector(mumboJumbo:)userInfo:nil repeats:NO];
And add your code into a method like:
-(void)mumboJumbo:(id)sender{
HUD = [[MBProgressHUD alloc] initWithView:self.view];
[self.view addSubview:HUD];
HUD.delegate = self;
HUD.labelText = #"Adding User";
HUD.detailsLabelText = #"Please Wait";
[HUD showWhileExecuting:#selector(sendNewUserInformation) onTarget:self withObject:nil animated:YES];
}
If I understood correctly your problem that should work.

Loading xib from UIAlertView from a viewcontroller

In my app I have a xib that has several viewcontrollers and xibs (with more viewcontrollers)off of it.
I can go from xib to xib and load what ever view controllers I want.
My problem is when I go to a view in side one off my viewcontrollers (be it on the main xib or another) I have a navigation bar at the bottom with a single button marked "back". Now when this button is hit before it takes you back It asks if you want something to happen.
When you click yes a UIAlertView will pop up and tell you wants about to happen when you click "ok". I know my button is firing by NSLogging my tag.
However I need a certain xib file to load and it does not.
This is the code that I am trying to use -- now this works If I want to go from xib to xib from a button. So I am not sure why its not working in an alert view.
- (void)alertView:(UIAlertView *)alert clickedButtonAtIndex:(NSInteger)buttonIndex {
// the user clicked one of the OK/Cancel buttons
if(alert.tag==1)
{
if (buttonIndex==0) {
ControllPanelViewController *controllpanel = [[ControllPanelViewController alloc] initWithNibName:nil bundle:nil];
[self presentModalViewController:controllpanel animated:YES];
NSLog(#"index 0");
}
}
}
Adding pic do to a response:
I have had similar problems before, not with a UIViewController, but with a UIActionSheet. When I tried to do this, I wanted to present a UIActionSheet depending on the selection of the UIAlertView. When I pressed something in the UIAlertView, the view was dismissed, but my action sheet was not shown. This was my solution; instead of:
if(alert.tag==1) {
if (buttonIndex==0) {
ControllPanelViewController *controllpanel = [[ControllPanelViewController alloc] initWithNibName:nil bundle:nil];
[self presentModalViewController:controllpanel animated:YES];
NSLog(#"index 0");
}
}
try something like:
if(alert.tag==1)
if (buttonIndex==0)
[self performSelector:#selector(presentController) withObject:nil afterDelay:.1];
with the method presentController being:
ControllPanelViewController *controllpanel = [[ControllPanelViewController alloc] initWithNibName:nil bundle:nil];
[self presentModalViewController:controllpanel animated:YES];
NSLog(#"index 0");
The problem seems to be that the UIAlertView takes some time to dismiss itself (very small amount of time) and in that time presenting another view doesn't work.
Also, as Alan Zeino said, if the name of the xib is not the same as the name of the view controller (for example if you have two different xibs- one for ipad and one for iphone), then you do need to specify which to use. If the name of the xib is the same as the view controller, you do not have to specify a name.
Edit:
If you want to use an action sheet and expect the delegate methods to work when their actions are triggered, you'd better set the delegate of the action sheet to self and in your interface file add the protocol.
You need to specify the xib you want to open:
ControllPanelViewController *controllpanel = [[ControllPanelViewController alloc] initWithNibName:#"XibNameHere" bundle:nil];
Since you have indicated that your log statement confirms correctly setting delegate and implementing the methods, the 'UIAlertView locks the screen' theory seems the only expectable one.
As Rickay has said performSelector:AfterDelay: would likely work, but as he has also said that requires a second method to be created. I would say that this is the perfect time for a block.
Here are a couple of options: Either should be copy and paste solutions.
1) Assuming the current main runloop simply has to finish it's current call stack before the new view controller can be pushed you could use:
-(void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex{
if (alertView.tag == 1) {
if (buttonIndex == 0) {
dispatch_async(dispatch_get_main_queue(), ^{
ControllPanelViewController *controllpanel = [[ControllPanelViewController alloc] initWithNibName:nil bundle:nil];
[self presentModalViewController:controllpanel animated:YES];
});
}
}
}
This will add a block to the main queue that will create and show your ControllPanelViewController as soon as the main run loop becomes available.
If, however, that doesn't work and it is 'just a matter of time', a block will still work. Like So:
-(void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex{
if (alertView.tag == 1) {
if (buttonIndex == 0) {
double delayInSeconds = 0.1;
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC);
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
ControllPanelViewController *controllpanel = [[ControllPanelViewController alloc] initWithNibName:nil bundle:nil];
[self presentModalViewController:controllpanel animated:YES];
});
}
}
}
This will create a block that will 'fire' in the number of seconds specified. Here set to 0.1 seconds.
Again the first one is a cleaner, arguably better, and much easier to read option.

How to show MBProgressHUD on iPhone without spawning new threads?

I want to show an MBProgressHUD in my iPhone app without spawning new threads.
I have a very complicated set of business logic which sometimes (but not always) needs to wait for user input, and running on multiple threads ends up asking for user input multiple times at once, leading to crazy errors. Thus I would prefer to avoid running anything off of the main thread. However, due to this constraint, MBProgressHUD is not showing because the main thread is being blocked! Normally I would create my MBProgressHUD with the following code:
[HUD showWhileExecuting:#selector(myWorkerMethod) onTarget:self withObject:nil animated:YES];
But I would like to use the following code without blocking the main thread:
HUD = [[MBProgressHUD alloc] initWithView:self.view];
[self.view addSubview:HUD];
HUD.delegate = self;
HUD.minShowTime = 0.0;
HUD.labelText = #"some text";
[HUD show:YES];
Any thoughts?
How about this?
MBProgressHUD *HUD = [MBProgressHUD showHUDAddedTo:self.view animated:YES];
HUD.labelText = #"Foo";
// code to execute synchronously
[MBProgressHUD hideHUDForView:self.view animated:YES];
Better late than never. You can do this with some run loop tickery. See this answer for details.