3

I'm pretty new on iOS development and I'm having the following problem. I need to fill a UITableView with data fetched from a server.

I'm doing this call using AFNetworking. I want to show a "loading view" using SVProgressHUD and I'm doing the following:

-(void) viewDidLoad{
    [super viewDidLoad];
    [SVProgressHUD showWithMaskType:SVProgressHUDMaskTypeGradient];
    [[MyServer sharedManager] fetchFromServerwithCompletionHandler:^(NSArray *elements, BOOL error) {
        _elements = elements;
        [_elementsTableView reloadData];
        [SVProgressHUD dismiss];
    }];
}

I'm getting the correct answer from the server but the progress hud is not being displayed. The call to the server does take some seconds so there is time for the progress hud view to be loaded but nothing happens.

I'm performing the call in the viewDidLoad because I need the call to be made as soon as the view is loaded and I want to call this just once.

If I move this block of code to the viewDidAppear the progress hud loads, but then this method is going to be called every-time the view is shown and I don't want this...

Thanks a lot!

Peter
  • 33
  • 3

2 Answers2

0

A trick can be use NSUserDefaults to save a value like @"serverAlreadyCalled" and check on viewDidAppear if you called the server before. example:

-(viewDidAppear){
NSUserDefaults* defaults = [NSUserDefaults standardDefaults];

if ([defaults valueForKey:@"serverAlreadyCalled"] == nil) {

[SVProgressHUD showWithMaskType:SVProgressHUDMaskTypeGradient];
[[MyServer sharedManager] fetchFromServerwithCompletionHandler:^(NSArray *elements, BOOL error) {
    _elements = elements;

    [defaults setValue:@"YES" forKey:@"serverAlreadyCalled"];
    [_elementsTableView reloadData];
    [SVProgressHUD dismiss];
}];
}
}

Don't forget to set nil to your key @"serverAlreadyCalled" before your app finishes run.

Maybe it's not the best solution, but can make the trick. Hope it helps.

scollaco
  • 947
  • 8
  • 13
  • Its bad practice to maintain single call using bool variable in this scenario. – Tirth Nov 29 '13 at 02:49
  • but why is not being shown in viewDidLoad? do you know? the server call takes like 3 seconds... (I agree with @Reformer) – Peter Nov 29 '13 at 02:51
  • As I said before, maybe it's not the best solution. I use to create a class to manage the communication with the server and use delegates to give some feedback for the user. – scollaco Nov 29 '13 at 10:48
0

The problem is not that the network call doesn't take place if done in viewDidLoad (because that is the right place to do it), but rather that the attempt to add the SVProgressHUD in viewDidLoad won't work, because this is too early in the process of constructing the view for SVProgressHUD to figure out where to put the HUD.

One simple solution would be to have viewDidLoad defer the invocation of this, to give the UI a chance to get to a state that SVProgressHUD can correctly place itself in the view hierarchy. As silly as it seems, you can just dispatch the code back to the main loop, which gives the UI a chance to catch up:

- (void)viewDidLoad
{
    [super viewDidLoad];

    dispatch_async(dispatch_get_main_queue(), ^{
        [SVProgressHUD showWithMaskType:SVProgressHUDMaskTypeGradient];
        [[MyServer sharedManager] fetchFromServerwithCompletionHandler:^(NSArray *elements, BOOL error) {
            _elements = elements;
            [_elementsTableView reloadData];
            [SVProgressHUD dismiss];
        }];
    });
}
Rob
  • 415,655
  • 72
  • 787
  • 1,044