how to use MBProgressHUD to pause the screen when the loading animating - ios

I have a problem.
I use MBProgressHUD in my tableviewcontroller.
I want that the MBProgressHUD loading animating then user can't touch anything and wait to get server data to show on the tableview.
I want to pause screen until hud hideAnimated.
Thanks!
This is my code:
MBProgressHUD *hud = [MBProgressHUD showHUDAddedTo:self.listTableView animated:YES];
hud.label.text = #"Loading";
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, 0.01 * NSEC_PER_SEC);
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
[self getInfo:nil];
});
hud.userInteractionEnabled = YES;
[hud hideAnimated:YES afterDelay:2];

You shouldn't use [hud hideAnimated:YES afterDelay:2] in this case. There is no point in dispatch_after either.
The thing is that your request may finish really quick (like 0.1 sec) and the hud will be still shown for another 1.9 sec. Or it may stay pending for a really long time, like 30 seconds or whatever timeout you set, so your code will hide the hud when it should actually be shown.
What you should do is to call completion blocks (or delegate methods) when the request is finished (successfully or not).
MBProgressHUD *hud = [MBProgressHUD showHUDAddedTo:self.view animated:YES];
hud.label.text = #"Loading";
[self getInfoWithSuccess:^{
[hud hideAnimated:YES];
//your code here
} failure:^(NSError *error) {
[hud hideAnimated:YES];
//show error message if needed
}];
Request method itself:
- (void) getInfoWithSuccess: (void(^)()) success failure: (void(^)(NSError *)) failure {
//do async request here and call success or failure block when it's finished
}

Related

Sleep function in iOS with Spinner

I have a spinner function to start and stop from beginning of process to end. But since process takes milliseconds, i can't really keep spinner turning.
[NSThread sleepForTimeInterval:2.0]; //method 1
sleep(2); //method2
Then i used Sleep methods to standby the code and let spinner turn, but it stops the Thread, then spinner will stop as well. This is the code:
if (indexPath.row == 1)
{
[MBProgressHUD showHUDAddedTo:self.view animated:YES]; //spinner starts
EmployeeDataSource *aaa=[[EmployeeDataSource alloc]init];
[aaa Logout: ^(BOOL results){
if(results == YES){
[NSThread sleepForTimeInterval:2.0]; //sleeping thread
//if logout succesfull go to login page
LoginViewController *lv = [self.storyboard instantiateViewControllerWithIdentifier:#"loginsb"];
[self presentViewController:lv animated:NO completion:nil];
[MBProgressHUD hideAllHUDsForView:self.view animated:YES]; //spinner ends
}
else{
NSLog(#"logout not succesfull");
}
}];
I want [MBProgressHUD showHUDAddedTo:self.view animated:YES]; to work for 2 seconds at least, but it ends in less than a second since normal process is fast? How can i extend this time, sleep method seems not suitable. Do you have any idea? Thank you.
i think you should do your stuff after some delay.
for that please use this
[self performSelector:#selector(method) withObject:nil afterDelay:1.0];
here Delay is in second, so you can set it accordingly.
Or you can go with this as well.
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, 0.5 * NSEC_PER_SEC);
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
//Do you stuff here...
});
May this help you.

Allow UI updates iOS

Let's say I do something like this:
[MBProgressHUD showHUDAddedTo:self.view animated:YES];
[self methodThatTakesLotsOfTime];
[MBProgressHUD hideHUDForView:self.view animated:YES];
This will won't allow enough time for the HUD to animate in and show. Using sleep(100) or an NSTimer will only add to the issue. I can't run the method on the main queue either. Not to mention dispatch_get_current_queue() is deprecated for iOS 6.0+. I must be missing something big
You can try using a transaction completion handler:
[MBProgressHUD showHUDAddedTo:self.view animated:YES];
[CATransaction setCompletionBlock: ^{
[self methodThatTakesLotsOfTime];
}];
But really that's just a stopgap. It is up to the authors of the code you are using to give you a way to animate with a completion block.

Delay a method call in objective-c

I know this can be done by using:
[self performSelector:#selector(myMethod) withObject:nil afterDelay:3.0]
However, the problem is that I want only 1 method call do be done.
With this function the calls will stack on top of each other. I want to make a call and if another call is made the first one will be dismissed. Ideas?
Once the method is executing then there is no way of stopping it.
But you can cancel if it is not fired. You can do something like this
//.... your code
[NSObject cancelPreviousPerformRequestsWithTarget:self selector:#selector(myMethod) object:nil];
[self performSelector:#selector(myMethod) withObject:nil afterDelay:3.0];
//.... your code
In this way you can cancel previous perform request only if the myMethod is not being fired.
In the Code Snippet Library in Xcode you can find one called GCD: Dispatch After, which looks like this:
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#>
});
Pretty self-explanatory.
EDIT: Now that I know that you want to only use the most recent, you could instead use:
[self cancelPreviousPerformRequestsWithTarget:self selector:#selector(myMethod) object:nil];
See this link for more info.
ORIGINAL POST:
You could just have a BOOL that is set to NO when it reaches that section and is then reset to YES after the method is performed.
So, for example, it would look something like:
if (boolVal) {
boolVal = NO;
[self performSelector:#selector(myMethod) withObject:nil afterDelay:3.0];
}
then in your myMethod, have:
boolVal = YES;
You should perform this selector in some other thread to avoid stack as you asked.
use
[self performSelector:(SEL) onThread:(NSThread *) withObject:(id) waitUntilDone:(BOOL)];
In that selector you can add delay what ever you want. As this process will run in separate thread so will not stop others for the delay

Make iOS not to wait until the entire method is finished to start animation

I have a method refreshDataAction:
- (void)refreshDataAction
{
MBProgressHUD *hud = [MBProgressHUD showHUDAddedTo:self.view animated:YES];
hud.labelText = #"Loading Data.Please Wait";
[self deletePreviousValues];
dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{
NSLog(#"Getting customer values");
[self getAllCustomerValues];
NSLog(#"Got customer values");
NSError *nwerror = nil;
if (![self.secondMOC save:&nwerror])
{
NSLog(#"209 Failed to save second MOC");
}
else
{
//NSLog(#"saved success");
}
dispatch_async(dispatch_get_main_queue(), ^{
[MBProgressHUD hideHUDForView:self.view animated:YES];
});
NSLog(#"Saved");
});
NSLog(#"Dispatched");
}
So as soon as the refreshDataAction starts i should see the HUD. But no its like waiting for 13 seconds before showing the HUD. I have no idea why it is happening like that. I tried different one like ActivityIndicator, but to no avail. Why is my app waiting 13 seconds to start the hud. On simulator its instant. I click button and i see HUD. But on the device 13 second delay. Start the hud immediately while background thread is doing some work. Please help. Spent the entire 5 hours figuring out ways to do this task.
There is my question here :UIAlertview hanging while the thread in background is loading data
I changed it to MBProgressHUD. May be some developers who have worked with MBProgressHUD could see this problem.
Is my main UI thread in some sort sleep mode for 13 seconds? I really dont know at this point. FYI, it's in iOS 6.0. This is an in-house iPad app. If you need more info, do ask.Thanks
I'd add the following to your viewDidLoad.
HUD = [[MBProgressHUD alloc] initWithView:self.navigationController.view];
[self.navigationController.view addSubview:HUD];
HUD.delegate = self;
HUD.labelText = #"";
HUD.mode = MBProgressHUDModeIndeterminate;
Then you can simply call the following methods without the dispatch_get_main_queue().
[HUD show:YES];
and...
[HUD hide:YES];

Adding a completion call back for MBProgressHUD

I would like to add a completion callback on my method so that the progress of the HUD knows it is complete.
MBProgressHUD *hud = [MBProgressHUD showHUDAddedTo:self.view animated:YES];
hud.mode = MBProgressHUDModeAnnularDeterminate;
hud.labelText = #"Loading";
[self doSomethingInBackgroundWithProgressCallback:^(float progress) {
hud.progress = progress;
} completionCallback:^{
[MBProgressHUD hideHUDForView:self.view animated:YES];
}];
What would I need to add to my method to confirm it is complete, or trigger this completionCallback from above?
In this case my method could be anything for example:
-(void)doSomethignInBackgroundWithProgressCallback {
sleep(100);
}
In case of HUD you can use its delegate function hudWasHidden which will when you use HUD like this -
[HUD showWhileExecuting:#selector(your_function) onTarget:self withObject:nil animated:YES];
and if you want to know how to use callbacks in objective c then follow this post -
http://stackoverflow.com/questions/1015608/how-to-perform-callbacks-in-objective-c
completion callback method -
- (void) doSomethingInBackground:(void (^) (void)) completion
{
// do your job here
completion();
}

Resources