Can someone explain to me what this error message is saying?
Assertion failed: ([NSThread isMainThread]), function -[AFContextManager addContextProvider:], file /SourceCache/MobileAssistantFramework/MobileAssistantFramework-651.49/AFContextManager.m, line 113.
This only happens about 1/8 of running my application.
I believe the last line of code in this snippet is causing it.
HUD = [[MBProgressHUD alloc]initWithView:self.view];
HUD.labelText = #"Scanning..";
[self.view addSubview:HUD];
[HUD showWhileExecuting:#selector(scanWithImage:) onTarget:self withObject:image animated:YES];
Force it to run on the main thread. Like this
dispatch_sync(dispatch_get_main_queue(), ^{
HUD = [[MBProgressHUD alloc]initWithView:self.view];
HUD.labelText = #"Scanning..";
[self.view addSubview:HUD];
[HUD showWhileExecuting:#selector(scanWithImage:) onTarget:self withObject:image animated:YES];
});
This assumes that the UI is not blocking while executing the above code and that you ABSOLUTELY want it to be synchronous. Else its very safe to use dispatch_async
Try this:
HUD = [MBProgressHUD showHUDAddedTo:self.view animated:YES];
HUD.labelText = #"Scanning..";
[HUD showWhileExecuting:#selector(scanWithImage:) onTarget:self withObject:image animated:YES];
Hope this helps.. :)
The addContextProvider: method is asserting that it is being run on the main thread. Likely the issue is that a method you must call from the main thread is being called from a background thread.
Related
I have been getting this error when trying to present the contact book view controller after a long process is complete.
Here is how I am running the process and showing the HUD.
HUD = [MBProgressHUD showHUDAddedTo:self.view animated:YES];
HUD.labelText = #"Scanning...";
UIFont *font = [UIFont fontWithName:#"HelveticaNeue-Light" size:20];
[HUD setLabelFont:font];
[HUD showWhileExecuting:#selector(scanWithImage:) onTarget:self withObject:_image animated:YES];
Here is how I am hiding the HUD and showing the contact book vc, which is called in scanImage.
dispatch_async(dispatch_get_main_queue(), ^(void){
[HUD hide:YES];
});
[self presentViewController:navigation animated:YES completion:nil];
Can anyone tell me how to resolve this issue?
Full error message:
Assertion failed: ([NSThread isMainThread]), function -[AFContextManager addContextProvider:], file /SourceCache/MobileAssistantFramework/MobileAssistantFramework-651.49/AFContextManager.m, line 113.
I guess you are trying to present the new controller from the background thread. Anything with respect to User interface including presenting a new controller cannot be performed from the background thread. So present the new controller from the main thread. Try this
dispatch_async(dispatch_get_main_queue(), ^(void){
[HUD hide:YES];
[self presentViewController:navigation animated:YES completion:nil];
});
I'm using MBProgressHUD in my app to make it more clear to the user when the app is waiting for the network.
My app is littered with calls to MBProgressHUD.
Example:
[MBProgressHUD showHUDAddedTo:self.view animated:YES];
[User findBy:#{#"email": email} success:^(NSDictionary *user) {
[MBProgressHUD hideHUDForView:self.view animated:YES];
So every network call is wrapped in an MBprogress show and then hide. There's gotta be a cleaner way.
I'd like to do this on a global level so that when there's network activity then the HUD comes on, when it stops then the HUD turns off.
How can I make the HUD mimic what the iPhone network activity indicator is doing?
I didn't see any API for this.
Note: I'm using AFNetworking 2.0
It should be simple.
You need to locate the "Top" most method that all or most of the requests use (Probably in the your implementation of AFnetworking request.
Use the app window to present the hud so you can present it from you AFNetworking class. Simply add this 2 methods to your class -
+ (MBProgressHUD *)showNetworkHUDWithTitle:(NSString *)title {
UIWindow *window = [[[UIApplication sharedApplication] windows] lastObject];
[MBProgressHUD hideAllHUDsForView:window animated:YES];
MBProgressHUD *hud = [MBProgressHUD showHUDAddedTo:window animated:YES];
hud.labelText = title;
return hud;
}
+ (void)dismissNetworkHUD {
UIWindow *window = [[[UIApplication sharedApplication] windows] lastObject];
[MBProgressHUD hideHUDForView:window animated:YES];
}
you can also check one of MBProgressHUD "show while" methods -
-(id)showAnimated:(BOOL)animated whileExecutingBlock:(dispatch_block_t)block;
- (void)showAnimated:(BOOL)animated whileExecutingBlock:(dispatch_block_t)block completionBlock:(MBProgressHUDCompletionBlock)completion;
- (void)showAnimated:(BOOL)animated whileExecutingBlock:(dispatch_block_t)block onQueue:(dispatch_queue_t)queue;
- (void)showAnimated:(BOOL)animated whileExecutingBlock:(dispatch_block_t)block onQueue:(dispatch_queue_t)queue
completionBlock:(MBProgressHUDCompletionBlock)completion;
this way the hud will disappear at the end of the execution.
I am using MBProgressHUD to show a HUD but it is not showing as expected.
Steps:
User selects a cell in a tableView. Some data is parsed then a warning (UIAlertView) is shown to the user. The user is asked if they want to create a New Game with the selected (cell) user. Cancel/Start Game buttons.
The UIAlertView delegate methods is as follows:
pragma mark - UIAlertView Delegate
-(void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
NSLog(#"button %i",buttonIndex);
if (buttonIndex == 0) {
// Cancel button pressed
self.gameNewOpponentuser = nil;
} else {
// Start Game button pressed
[MESGameModel createNewGameWithUser:[PFUser currentUser] against:self.gameNewOpponentuser];
}
}
If the user selects Start Game the GameModel method is run. The game model(NSObject subclass) method is as follows:
pragma mark - Custom method
+(void)createNewGameWithUser:(PFUser *)user1 against:(PFUser *)user2 {
// First we put a HUD up for the user on the window
MBProgressHUD *HUD = [[MBProgressHUD alloc] initWithWindow:[UIApplication sharedApplication].keyWindow];
HUD.dimBackground = YES;
HUD.labelText = NSLocalizedString(#"HUDCreateNewGame", #"HUD - Create New Game text");
HUD.removeFromSuperViewOnHide = YES;
// Confirm we have two users to play with.
}
As you can see the HUD is alloc init to the keywindow of the application. However, the HUD is not showing as expected, nothing happens no UI lockup etc. I have put a breakpoint in the above method and can see that it is called however the HUD is not displayed
From the above, I expect the HUD to show up but nothing else happen, i.e. the HUD just remain on screen at the moment...
You are missing the part where you add the HUD to the Window and then showing the HUD. Note that you can add the HUD to the Window or the current view (self.view).
MBProgressHUD *HUD = [[MBProgressHUD alloc] initWithWindow:[UIApplication sharedApplication].keyWindow];
[[UIApplication sharedApplication].keyWindow addSubview:HUD]; //<-- You're missing this
HUD.dimBackground = YES;
HUD.labelText = NSLocalizedString(#"HUDCreateNewGame", #"HUD - Create New Game text");
HUD.removeFromSuperViewOnHide = YES;
[HUD showAnimated:YES whileExecutingBlock:^{ //<-- And this
// Do something
}];
Try this:
MBProgressHUD *HUD = [[MBProgressHUD alloc] initWithView:self.view];
HUD.labelText = NSLocalizedString(#"HUDCreateNewGame", #"HUD - Create New Game text");
// Set determinate mode
[HUD setMode:MBProgressHUDModeDeterminate];
[self.view addSubview:HUD];
[HUD show:YES];
You aren't adding it to any view for it to be displayed. So add it to appropriate view.
From the git hub project demo for MBProgressHUD
// The hud will dispable all input on the view (use the higest view possible in the view hierarchy)
HUD = [[MBProgressHUD alloc] initWithView:self.navigationController.view];
[self.navigationController.view addSubview:HUD];
You are not given the code to display the hud. use the following code
MBProgressHUD *HUD = [MBProgressHUD showHUDAddedTo:self.view animated:YES];
HUD.dimBackground = YES;
HUD.labelText = NSLocalizedString(#"HUDCreateNewGame", #"HUD - Create New Game text");
Ok, I found the issue. I was using clickedButtonAtIndex method for the UIAlertView which was of course holding to the view. I used didDismissWithButtonIndex instead and this works fine now.
I have a uitableview which loads data from internet and during this period im displaying MBProgressHUD. But the problem is the user cannot touch anything including previous page button before the table loads. Here is my codein two different classes:
//PROBLEM METHOD 1
- (void)viewDidLoad
{
[super viewDidLoad];
[tableEtkinlikler reloadData];
MBProgressHUD *HUD = [MBProgressHUD showHUDAddedTo:self.view animated:YES];
HUD.labelText = #"Açılıyor...";
HUD.userInteractionEnabled = NO;
[self performSelector:#selector(loadEtkinliklerTitlesAndImages) withObject:nil afterDelay:0];
tableEtkinlikler.dataSource = self;
tableEtkinlikler.delegate = self;
}
I have the same problem with a button also..In it im loading data from internet..
//PROBLEM METHOD 2
- (IBAction)AktivitelerButtonClicked:(UIButton *)sender
{
MBProgressHUD *HUD = [MBProgressHUD showHUDAddedTo:self.view animated:YES];
HUD.labelText = #"Açılıyor...";
HUD.userInteractionEnabled = NO;
[self performSelector:#selector(openAktivitelerWindow) withObject:nil afterDelay:0];
}
I believe for me that is the point of MBProgressHUD , it gives you the opportunity show a HUD while your tasks are completed, once your tasks are completed you dismiss it so user can interact with completed data.
However In some cases loading data takes so long so you might want to let the user decide to continue , choose another option or just simply go back
in your code this HUD.userInteractionEnabled = NO; should work but problem might be that showHUDAddedTo:self.view you do not use the highest view possible in the view hierarchy.
Try to use this:
- (IBAction)showSimple:(id)sender {
// The hud will dispable all input on the view (use the higest view possible in the view hierarchy)
HUD = [[MBProgressHUD alloc] initWithView:self.navigationController.view];
[self.navigationController.view addSubview:HUD];
HUD.userInteractionEnabled = NO;
// Regiser for HUD callbacks so we can remove it from the window at the right time
HUD.delegate = self;
// Show the HUD while the provided method executes in a new thread
[HUD showWhileExecuting:#selector(loadEtkinliklerTitlesAndImages) onTarget:self withObject:nil animated:YES];
}
I'm trying to show a mix of HUDs in my app, so for example, when a user taps "login", I want my HUD to display the spinner saying "logging in...", then change to a checkmark image saying "logged in!", then hide. I'm trying to accomplish this using the following code:
MBProgressHUD *HUD = [MBProgressHUD showHUDAddedTo:self.view animated:YES];
HUD.labelText = #"Logging in";
\\Do network stuff here, synchronously (because logging in should be synchronous)
\\ Then upon success do:
HUD.customView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"checkmark.png"]];
HUD.mode = MBProgressHUDModeCustomView;
HUD.labelText = #"Logged in!";
sleep(2);
[MBProgressHUD hideHUDForView:self.view animated:YES];
Problem here, is that the sleep(2) is being applied to the initial spinner, and not the checkmark HUD. So the spinner is showing for a longer period of time, and the checkmark disappears after a split second. How can I do it so that the checkmark stays there for a longer time before the HUD hides?
Thanks!
As best practice, don't use sleep. Try using the "performSelector:withObject:afterDelay" method. Create a method that does the
[MBProgressHUD hideHUDForView:self.view animated:YES];
action and call it after a predefined delay of your choice. Don't forget that you're handling UI so make sure you're calling this on the main thread.
I would create two HUDs. The first one for the "waiting" part, and the second one for the success. Start the loadingHUD before your network task, and hide it when you are done :
MBProgressHUD *loadingHUD = [MBProgressHUD showHUDAddedTo:self.view animated:YES];
loadingHUD.mode = MBProgressHUDModeIndeterminate;
loadingHUD.labelText = #"Please wait...";
loadingHUD.detailsLabelText = #"Connection in progress";
[loadingHUD show:YES];
// Do the network stuff here
[loadingHUD hide:YES];
Right after that, to notify the success, create the successHUD as you want it, and hide it after delay :
MBProgressHUD *successHUD = [MBProgressHUD showHUDAddedTo:self.view animated:YES];
successHUD.mode = MBProgressHUDModeCustomView;
successHUD.customView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"checkmark.png"]];
successHUD.labelText = #"Logged in !";
[successHUD show:YES];
[successHUD hide:YES afterDelay:2.0];
Your success HUD will show up for 2 seconds, and hide automatically.
That's how I always use MBProgressHUD.