Advertisement
If you have a new account but are having problems posting or verifying your account, please email us on hello@boards.ie for help. Thanks :)
Hello all! Please ensure that you are posting a new thread or question in the appropriate forum. The Feedback forum is overwhelmed with questions that are having to be moved elsewhere. If you need help to verify your account contact hello@boards.ie
Hi there,
There is an issue with role permissions that is being worked on at the moment.
If you are having trouble with access or permissions on regional forums please post here to get access: https://www.boards.ie/discussion/2058365403/you-do-not-have-permission-for-that#latest

Obj-C iPhone - MBProgressHUD / Managing Views

  • 17-05-2011 3:30pm
    #1
    Registered Users, Registered Users 2 Posts: 8,004 ✭✭✭


    Hi Folks,

    This is probably a very stupid question but I can't get my head around it. In my App I have one class that handles all downloads and file saving. Its called DatabaseIO. It has no view associated with it and is readily usable by all other class's.

    The problem is I want to put in two functions to allow MBProgressHUD to show on whatever view is currently presented to the user e.g. When the user downloads, I want MBProgress to present a loading screen etc.

    My best attempt so far is this:
    -(void) showHUD {
    	
    	NSLog(@"Show HUD - DatabaseIO");
    	[UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
    	
    	UIWindow *window = [UIApplication sharedApplication].keyWindow;
    
    	
    	HUD = [[MBProgressHUD alloc] initWithWindow:[UIApplication sharedApplication].keyWindow];
    	
    	[window addSubview:HUD];
    	HUD.labelText = @"Loading Database";
    	[HUD show:YES];
    	
    	
    		
    }
    

    But its fairly sporadic and when combined with Async downloads, it has a habit of half working or staying stuck on the screen.

    The method to download a database is called

    -(void)downloadDatabase

    Which in turn calls a connection method and saves to the file system of the iphone.


    Could anyone cast some light on how I would have to implement and call the showHUD method? And subsequently make it disappear when the download is complete?

    Many Thanks


Comments

  • Registered Users, Registered Users 2 Posts: 981 ✭✭✭fasty


    What happens inside the download database method? Does it make some sort of ASync call to fetch the data?

    If so, do you specify some sort of callback selector or implement pass some object as a delegate that would get told when the download is complete?

    That's where I usually hide progress views.
    - (void)refresh
    {
       // Show HUD
       [dataContext query:kQuery target:self selector:@selector(queryResult:error:context:) context:nil];
    }
    
    - (void) queryResult:(queryResult *)result error:(NSError *)error context:(id)context
    {
       if(error != nil)
       {
          // Handle error
       }
       
       // Do stuff with data
       // Hide progress indicator or remove it from the view or whatever
    }
    

    It's the same idea if you set some sort of delegate instead of passing a target and selector. When your download is done, hide the HUD.


  • Registered Users, Registered Users 2 Posts: 8,004 ✭✭✭ironclaw


    The problem isn't calling the HUD, thats fine. Its trying to make it show regardless of what view the user is in.

    i.e. Main Menu > Refresh DB > Show HUD

    or Deep Menu > Refresh DB > Show HUD

    With showHUD always being called in DatabaseIO. So it may not know what view the user is in. I suppose what I'm looking to do is programmically always put the HUD on the upper most view.


  • Registered Users, Registered Users 2 Posts: 981 ✭✭✭fasty


    In my opinion, the solution is still the same, but you'd keep the show/hide HUD functions somewhere common, like in you App Delegate and pass the view as a param.

    Don't call view stuff from a database IO function. From the view controller you'd show the HUD, passing the current view, refresh the DB and when the DB is finished it's work, hide the HUD. It's just a matter of encapsulating the state you need.


  • Registered Users, Registered Users 2 Posts: 8,004 ✭✭✭ironclaw


    fasty wrote: »
    In my opinion, the solution is still the same, but you'd keep the show/hide HUD functions somewhere common, like in you App Delegate and pass the view as a param.
    .

    Thanks fasty. Would you be able to show me how to do that? Even in Pseudo code?

    Ok, small edit. Moved the HUD set up to the App delegate.
    HUD showWhileExecuting:@selector(myTask) onTarget:self withObject:nil animated:YES];
    

    How would I edit the selector calling "myTask" to call a method in DatabaseIO called -(void)downloadDatabase

    I'm probably doing this totally wrong but I want to keep all the internet / download methods in the one class.

    In another class I call the dowload like this and it works fine:
    DatabaseIO *downloader = [[DatabaseIO alloc] init];
    
    [downloader downloadDatabase];
    
    [downloader release];
    
    


  • Registered Users, Registered Users 2 Posts: 981 ✭✭✭fasty


    I haven't tested this or anything, but if you specify your downloader as the target and downloadDatabase as the selector it might do the job.
    DatabaseIO *downloader = [[DatabaseIO alloc] init];
    [HUD showWhileExecuting:@selector(downloadDatabase) onTarget:downloader withObject:nil animated:YES];
    [downloader release];
    


  • Advertisement
  • Registered Users, Registered Users 2 Posts: 8,004 ✭✭✭ironclaw


    Cheers fasty. I tried that just before you posted it. It works but it seems the "downloader" object is released too early. The connection gets started but just stops, and the app delegate just motors along. :confused:

    When should I call [self showHUD]?
    - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {    
        
        // Override point for customization after application launch.
        [window addSubview:rootController.view];
        [self.window makeKeyAndVisible];
    	whereNavController.navigationBar.tintColor = [UIColor blackColor]; 
    	[self showHUD];
    return YES;
    
    


  • Registered Users, Registered Users 2 Posts: 981 ✭✭✭fasty


    Ah yeah, I posted in a hurry without thinking. The call to show the hud would return and your downloader would release.

    How I would do it would be to have a delegate or callback in the DatabaseIO class so it could tell any object who cares that it's finished downloading.
    @protocol DatabaseIODelegate
    -(void)databaseDidFinishDownloading;
    @end
    

    and in DatabaseIO
    @property (assign) <id>DatabaseIODelegate delegate;
    
    Then when you create your DatabaseIO object, when your database is finished downloading, call
    [delegate databaseDidFinishDownloading];
    
    ;

    So from whatever view controller you want, as long as it implements - (void)didFinishDownloading

    Create database io
    set it's delegate to self
    start db fetch
    create hud and show

    then in the didFinishDownloading method, you know it's done so hide the hud.

    Sorry if this is all a bit vague!


  • Registered Users, Registered Users 2 Posts: 8,004 ✭✭✭ironclaw


    Thanks again fasty. I'll have to step through this as I'm very new to delegates and callbacks.

    Where is this code implemented? In DatabaseIO.h?
    @protocol DatabaseIODelegate
    -(void)databaseDidFinishDownloading;
    @end
    


    This segment. Again, where would it be implemented?
    @property (assign) <id>DatabaseIODelegate delegate;
    

    Would this call be made in DatabaseIO or in the the class that is using the DatabaseIO instance?
    [delegate databaseDidFinishDownloading];
    
    ;


    I can see what you are trying to do and I understand the logic. I just don't have a clue how to implement it! :)


  • Registered Users, Registered Users 2 Posts: 981 ✭✭✭fasty


    No worries man, I think I could explain it much better if I could show you some working code, if you know what I mean!

    Anyway, the protocol would be in DatabaseIO.h above your declaration of the DatabaseIO class, the property would be IN the DatabaseIO declaration in DatabaseIO.h and the call to databaseDidFinishDownloading would be inside your downloadDatabase method.

    The idea of the protocol and delegates here is that the act as callbacks, telling any whatever class wants to know "I am done" which in this case would be a prompt to hid the progress hud!

    If you're still having problems after the weekend I'll try to knock together some sample code for you.


  • Registered Users, Registered Users 2 Posts: 8,004 ✭✭✭ironclaw


    Ok, did some tinkering and this code builds ok:

    DatabaseIO.h
    #import <UIKit/UIKit.h>
    
    [B]@protocol DatabaseIODelegate
    -(void)databaseDidFinishDownloading;
    @end[/B]
    
    
    
    @interface DatabaseIO : UIView <UIAlertViewDelegate> {
    	
    	NSArray *databaseDownloadArray;
    	NSMutableArray *wallImagesArray;
    	
    	[B]id <DatabaseIODelegate> delegate;[/B]
    
    
    }
    
    @property (nonatomic, retain) NSArray *databaseDownloadArray;
    @property (nonatomic, retain) NSMutableArray *wallImagesArray;
    [B]@property (retain) id delegate;[/B]
    

    DatabaseIO.m
    //Last line of Download method
    
    [delegate databaseDidFinishDownloading];
    
    


    Is that ok so far? How do I need to adjust showHUD in the App delegate to use this?


  • Advertisement
  • Registered Users, Registered Users 2 Posts: 8,004 ✭✭✭ironclaw


    Ok! We have success. Cheers fasty.

    For anyone who comes across this thread. Follow the excellent advice above and this tutorial: http://iphonedevelopertips.com/objective-c/the-basics-of-protocols-and-delegates.html


  • Registered Users, Registered Users 2 Posts: 981 ✭✭✭fasty


    Glad to hear it! Nice link too, does a good job of explaining it. Although you should never retain a delegate, always assign.

    If object A has a reference to object B and object B has a reference to object A, you would have a circular reference!


Advertisement