In one stack I am displaying the MBProgressHUD and if by using the other stack when some calculation called I want MBProgressHUD to remove from the view but it is not been removed from the hud ..check what mistake I am doing..
first stack called LoginViewController.m
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
[MBProgressHUD showHUDAddedTo:self.view animated:YES];
}
-(void)myTask {
// Do something usefull in here instead of sleeping ...
[MBProgressHUD hideHUDForView:self.view animated:YES];
[self.hud hide:YES];
self.hud=nil;
[self.hud removeFromSuperview];
//[self.hud showWhileExecuting:#selector(myTask1) onTarget:self withObject:nil animated:YES];
}
now theViewController get calls but view will be same Previous and
after some calculation and I want that in ViewController I want to remove theHUD from the view by calling the method in the LoginViewController..check code
- (void)didReceiveResponseFromServer:(NSString *)responseData
{
login=[[LoginViewController alloc]init];
[self.login myTask];
}
Set UP MBProgressHUD
- (void) setupHUD
{
//setup progress hud
self.HUD = [[MBProgressHUD alloc] initWithFrame:self.window.bounds];
[self.SpurView addSubview:self.HUD]; // add it as here.
self.HUD.dimBackground = YES;
self.HUD.minSize = CGSizeMake(150.f, 150.f);
self.HUD.delegate = self;
self.HUD.labelText = #"Loading...";
}
Then use for hide [self.HUD hide:YES]; as describe in your code .
like me ,
I tyr [MBProgressHUD hideHUDForView:bAnimatedView animated:YES]
but it will no work at times when I quick push in and back out .
So I add something to check the view of MBProgressHUD.
MBProgressHUD *HUD = [MBProgressHUD HUDForView:bAnimatedView];
if (HUD!= nil) {
[HUD removeFromSuperview];
HUD=nil;
}
In my Project, each of the user interaction events make a network call (Which is TCP, not HTTP). I need Activity Indicator to be global to show from a random UIViewController and hide from NetworkActivityManager Class (a custom class to handle network activities, Which is not a subclass of UIViewController or UIView).
After searching the web I found out that MBProgressHUD is used for the same purpose, but I wasn't able to find out an example on how would I use it globally. (By saying global I mean a singleton object of MBProgressHUD and class methods to SHOW and HIDE it.)
Following is what I have tried yet, but, failed:
In AppDelegate.h:
#property (nonatomic, retain) MBProgressHUD *hud;
In AppDelegate.m:
#synthesize hud;
In some random UIViewController object:
appDelegate.hud = [MBProgressHUD showHUDAddedTo:appDelegate.navigationController.topViewController.view animated:YES];
appDelegate.hud.labelText = #"This will take some time.";
And while hiding it, from NetworkActivityManager Class:
[MBProgressHUD hideHUDForView:appDelegate.navigationController.topViewController.view animated:YES];
This makes the project to crash after some time (due to memory issues.)
I am using ARC in my project and also, I am using the ARC version of MBProgressHUD.
Am I missing something?
Important Question:
Can I make MBProgressHUD work like UIAlertView? (Saying that I mean implementation of MBProgressHUD independent of UIView -- sa it uses showHUDAddedTo: to present itself) ???
Please Note: In the above code of hiding MBProgressHUD, View may be changed from what it was when showing MBProgressHUD.
Any Help greatly appreciated.
You could add this to a class of your liking:
+ (MBProgressHUD *)showGlobalProgressHUDWithTitle:(NSString *)title {
UIWindow *window = [[[UIApplication sharedApplication] windows] lastObject];
MBProgressHUD *hud = [MBProgressHUD showHUDAddedTo:window animated:YES];
hud.labelText = title;
return hud;
}
+ (void)dismissGlobalHUD {
UIWindow *window = [[[UIApplication sharedApplication] windows] lastObject];
[MBProgressHUD hideHUDForView:window animated:YES];
}
This can be than called on any class. You don't need to keep a strong reference to the HUD when using those class convenience methods.
Depending on your specific situation you'll probably also want to handle cases where a new hud is requested before the other one is hidden. You could eater hide the previous hud when a new comes in or come up with some sort of queueing, etc.
Hiding the previous HUD instance before showing a new one is pretty straightforward.
+ (MBProgressHUD *)showGlobalProgressHUDWithTitle:(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;
}
NOTE...
as with many iOS issues, this is now drastically, totally out of date.
These days you certainly just use a trivial
Container view
for any issue like this.
Full container view tutorial for beginners .. tutorial!
MBProgressHUD was a miraculous solution back in the day, because there was a "drastic hole" in Apple's pipeline.
But (as with many wonderful things from the past), this is only history now. Don't do anything like this today.
Just FWIW, 2014, here's a very simple setup we use. Per David Lawson...
UIWindow *window = [[UIApplication sharedApplication] delegate].window
as Matej says, just use AppDelegate...
#define APP ((AppDelegate *)[[UIApplication sharedApplication] delegate])
AppDelegate.h
// our convenient huddie system (messages with a hud, spinner)
#property (nonatomic, strong) MBProgressHUD *hud;
-(void)huddie;
AppDelegate.m
-(void)huddie
{
// centralised location for MBProgressHUD
[self.hud hide:YES];
UIWindow *windowForHud = [[UIApplication sharedApplication] delegate].window;
self.hud = [MBProgressHUD showHUDAddedTo:windowForHud animated:YES];
self.hud.dimBackground = YES;
self.hud.minShowTime = 0.1;
self.hud.labelText = #"";
self.hud.detailsLabelText = #"";
}
Set the titles in your code where you are using it - because you very often change them during a run. ("Step 1" ... "Step 2" etc)
-(void)loadBlahFromCloud
{
[APP huddie];
APP.hud.labelText = #"Connecting to Parse...";
APP.hud.detailsLabelText = #"step 1/2";
[blah refreshFromCloudThen:
^{
[... example];
}];
}
-(void)example
{
APP.hud.labelText = #"Connecting to the bank...";
APP.hud.detailsLabelText = #"step 2/2";
[blah sendDetailsThen:
^{
[APP.hud hide:YES];
[... showNewDisplay];
}];
}
Change huddle to take the texts as an argument if you wish
You always want self.hud.minShowTime = 0.1; to avoid flicker
Almost always self.hud.dimBackground = YES; which also blocks UI
Conceptually of course you usually have to "slightly wait" to begin work / end work when you bring up such a process, as with any similar programming with the UI.
So in practice code will usually look like this...
-(void)loadActionSheets
{
[APP huddie];
APP.hud.labelText = #"Loading json from net...";
dispatch_after_secs_on_main(0.1 ,
^{
[STUBS refreshNowFromCloudThen:
^{
[APP.hud hide:YES];
dispatch_after_secs_on_main(0.1 , ^{ [self buildActionsheet]; });
}];
}
);
}
Handy macro ..
#define dispatch_after_secs_on_main( SS, BB ) \
dispatch_after( \
dispatch_time(DISPATCH_TIME_NOW, SS*NSEC_PER_SEC), \
dispatch_get_main_queue(), \
BB \
)
This is all history now :) https://stackoverflow.com/a/23403979/294884
This answer is what I've been using for 5-6 Apps now because it works perfectly inside blocks too. However I found a problem with it. I can make it shown, but can't make it disappear if a UIAlertView is also present. If you look at the implementation you can see why. Simply change it to this:
static UIWindow *window;
+ (MBProgressHUD *)showGlobalProgressHUDWithTitle:(NSString *)title {
window = [[[UIApplication sharedApplication] windows] lastObject];
MBProgressHUD *hud = [MBProgressHUD showHUDAddedTo:window animated:YES];
hud.labelText = title;
return hud;
}
+ (void)dismissGlobalHUD {
[MBProgressHUD hideHUDForView:window animated:YES];
}
This will make sure you're removing the HUD from the same windows as it was shown on.
I found #Matej Bukovinski 's answer very helpful, since I just started using Swift and my purpose using his methods was to set a global font for the MBProgressHUD, I have converted the code to swift and am willing to share the code below:
class func showGlobalProgressHUDWithTitle(title: String) -> MBProgressHUD{
let window:UIWindow = UIApplication.sharedApplication().windows.last as! UIWindow
let hud = MBProgressHUD.showHUDAddedTo(window, animated: true)
hud.labelText = title
hud.labelFont = UIFont(name: FONT_NAME, size: 15.0)
return hud
}
class func dismissGlobalHUD() -> Void{
let window:UIWindow = UIApplication.sharedApplication().windows.last as! UIWindow
MBProgressHUD.hideAllHUDsForView(window, animated: true)
}
The above code is put into a global file where I keep all my global helpers and constants.
I've used it as below..Hope it helps you..
in appDelegate.m
-(void)showIndicator:(NSString *)withTitleString currentView:(UIView *)currentView
{
if (!isIndicatorStarted) {
// The hud will dispable all input on the view
self.progressHUD = [[[MBProgressHUD alloc] initWithView:currentView] autorelease];
// Add HUD to screen
[currentView addSubview:self.progressHUD];
self.progressHUD.labelText = withTitleString;
[window setUserInteractionEnabled:FALSE];
[self.progressHUD show:YES];
isIndicatorStarted = TRUE;
}
}
-(void)hideIndicator
{
[self.progressHUD show:NO];
[self.progressHUD removeFromSuperview];
self.progressHUD = nil;
[window setUserInteractionEnabled:TRUE];
isIndicatorStarted = FALSE;
}
From Random Views:-
[appDel showIndicator:#"Loading.." currentView:presentView.view];
Note: Considering the views this Question is getting I decided to post the the way I did choose as a solution. This is NOT an answer to my question. (Hence, the accepted answer remains accepted)
At that time I ended up using SVProgressHUD as it was very simple to integrate and use.
All you need to do is just drag the SVProgressHUD/SVProgressHUD folder into your project. (You may choose to go for cocoapods OR carthage, as well)
In Objective-C:
[SVProgressHUD show]; // Show
[SVProgressHUD dismiss]; // Dismiss
In Swift:
SVProgressHUD.show() // Show
SVProgressHUD.dismiss() // Dismiss
Additionally, Show and hide HUD needs to be executed on main thread. (Specifically you would need this to hide the HUD in some closure in background)
e.g.:
dispatch_async(dispatch_get_main_queue(), ^{
[SVProgressHUD dismiss]; // OR SHOW, whatever the need is.
});
There are additional methods for displaying custom messages with HUD, showing success/failure for short duration and auto dismiss.
MBProgressHUD still remains a good choice for developers. It's just that I found SVProgressHUD to suit my needs.
I was using the code from #Michael Shang and having all kinds of inconsistent behavior with showing HUDs. Turns out using the last window is unreliable as the iOS keyboard may just hide it. So in the majority of cases you should get the window using the AppDelegate as mentioned by #David Lawson.
Here's how in Swift:
let window = UIApplication.sharedApplication().delegate!.window!!
let hud = MBProgressHUD.showHUDAddedTo(window, animated: true)
However, with the above your HUD will show up behind the iOS keyboard (if they overlap). If you need your HUD to overlay the keyboard use the last window method.
In my case, what was happening is I would show the HUD then call resignFirstResponder() immediately hiding the window the HUD was added to. So this is something to be aware of, the only window guaranteed to stick around is the first one.
I ended up creating a method that could optionally add the HUD above the keyboard if needed:
func createHUD(size: CGSize, overKeyboard: Bool = false) -> MBProgressHUD {
let window = overKeyboard ? UIApplication.sharedApplication().windows.last!
: UIApplication.sharedApplication().delegate!.window!!
let hud = MBProgressHUD.showHUDAddedTo(window, animated: true)
hud.minSize = size
hud.bezelView.style = .SolidColor
hud.bezelView.color = UIColor(white: 0, alpha: 0.8)
return hud
}
To show the one MBProgressHUD at one time, you can check weather HUD is already added in same view or not. If not, then add the HUD otherwise do not add new HUD.
-(void)showLoader{
dispatch_async(dispatch_get_main_queue(), ^{
BOOL isHudAlreadyAdded = false;
UIWindow *window = [[[UIApplication sharedApplication] windows] lastObject];
NSEnumerator *subviewsEnum = [window.subviews reverseObjectEnumerator];
for (UIView *subview in subviewsEnum) {
if ([subview isKindOfClass:[MBProgressHUD class]]) {
isHudAlreadyAdded = true;
}
}
if(isHudAlreadyAdded == false){
[MBProgressHUD showHUDAddedTo:window animated:YES];
}
});
}
-(void)hideLoader{
dispatch_async(dispatch_get_main_queue(), ^{
UIWindow *window = [[[UIApplication sharedApplication] windows] lastObject];
[MBProgressHUD hideHUDForView:window animated:YES];
});
}
Add these two methods to show or hide loader in your singleton class
- (void)startLoaderWithText:(NSString *)title View:(UIView *)view{
progressHud = [MBProgressHUD showHUDAddedTo:view animated:YES];
progressHud.labelText = title;
progressHud.activityIndicatorColor = [UIColor grayColor];
progressHud.color = [UIColor clearColor];
[progressHud show:YES];
}
- (void)stopLoader{
[progressHud hide:YES];
}
New to objective c, and I am using ArcGIS for the map portion. I have a problem where the method mapViewDidLoad is not called/loaded. Here is some part of the code:
.h file
#interface ViewController : UIViewController<AGSMapViewLayerDelegate, AGSMapViewTouchDelegate, AGSMapViewCalloutDelegate>{
AGSMapView *_mapView;
AppDelegate *appDelegate;
...
}
.m file
- (void)viewDidLoad
{
[super viewDidLoad];
[self.activityView startAnimating];
self.mapView.touchDelegate = self;
self.mapView.calloutDelegate = self;
appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
CLLocationManager *locationManager = [[CLLocationManager alloc] init];
...
}
- (void)mapViewDidLoad:(AGSMapView *)mapView {
AGSEnvelope *envelope = [[AGSEnvelope alloc]initWithXmin:29757.610204117
ymin:40055.0379682464
xmax:29884.6992302249
ymax:40236.6028660071
spatialReference:self.mapView.spatialReference];
[self.mapView zoomToEnvelope:envelope animated:YES];
self.mapView.callout.width = 195.0f;
self.mapView.callout.accessoryButtonHidden = YES;
[self.mapView.gps start];
[self.mapView centerAtPoint:self.mapView.gps.currentPoint animated:YES];
NSLog(#"Location : %#", self.mapView.gps.currentPoint);
[self.activityView stopAnimating];
self.activityView.hidden = YES;
}
What is wrong with my code why i doesn't load the mapViewDidLoad method.
Thanks in advance.
make sure that mapviewdelegate is connected by right click on mapview and then assign delegate..
or add [self.mapview setDelegate:self];
in your case "AGSMapView" mapViewDidLoad: method on AGSMapViewLayerDelegate is invoked after the first layer has been added to the map. At this point, the component is fully functional you can find reference to it in
http://help.arcgis.com/en/arcgismobile/10.0/apis/iphone/reference/interface_a_g_s_map_view.html
make self.mapview.layerDelegate = self;
Just add self.mapView.delegate = self; in viewDidLoad
I've got both working great individually, but when I try to combine them like this:
- (IBAction)showWithLabel:(id)sender
{
HUD = [MBProgressHUD showHUDAddedTo:self.navigationController.view animated:YES];
[self.checkinsViewController.view addSubview:HUD];
HUD.delegate = self;
HUD.labelText = #"Sending tweet";
[HUD showWhileExecuting:#selector(tweet) onTarget:self withObject:nil animated:YES];
}
- (void)tweet { [_twEngine sendUpdate:#"Test tweet"]; }
I don't get any errors, but the tweet isn't sent If I place:
[_twEngine sendUpdate:#"Test tweet"];
In the IBAction, it tweets. If I change tweet to sleep, the HUD shows up properly.
Any ideas?
The showHUDAddedTo:animated: and showWhileExecuting: methods are mutually exclusive. You can't use both methods to show the HUD .
Change your initializer to just allocate a HUD and it should work.
HUD = [[MBProgressHUD alloc] initWithView:self.navigationController.view];
I currently have a UISearchBar and UIDisplayController defined in my RootViewController as:
- (void)viewDidLoad {
[super viewDidLoad];
//Add the search bar
aSearchBar = [[UISearchBar alloc] initWithFrame:CGRectZero];
[aSearchBar sizeToFit];
aSearchBar.delegate = self;
aSearchBar.placeholder = #"Search YouTube...";
self.tableView.tableHeaderView = aSearchBar;
searchDC = [[UISearchDisplayController alloc] initWithSearchBar:aSearchBar contentsController:self];
[self performSelector:#selector(setSearchDisplayController:) withObject:searchDC];
searchDC.delegate = self;
searchDC.searchResultsDataSource = self;
searchDC.searchResultsDelegate = self;
[aSearchBar release];
[searchDC release];
}
When the search button is fired, this event is executed to run an API call:
- (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar {
[videoList removeAllObjects];
if (searchBar.text.length > 0) {
NSString *searchCriteria = [searchBar.text stringByReplacingOccurrencesOfString:#" " withString:#"+"];
YTJAppDelegate *appDelegate=(YTJAppDelegate*)[[UIApplication sharedApplication] delegate];
[appDelegate searchWithCriteria:searchCriteria];
}
}
The data is fetched correctly. However. It only becomes visible when I hit the 'Cancel' button on the search.
How can I get the view to update correctly the moment the data source is updated/search button is hit? Is there a special SearchDelegate method I need to implement?
the code for the associated table view might be helpful, but I am going to guess that you are not calling [self.tableView reloadData] after the search is completed
turns out the solution was to point the searchDisplayController delegates and data sources at the table view it was implementing:
searchDC.delegate = self;
searchDC.searchResultsDataSource = self.tableView.dataSource;
searchDC.searchResultsDelegate = self.tableView.delegate;