Question

I know there have been a couple questions asked similar to this, but I think my issues is a little different, so bear with me.

I have a tabbed view app with table views set in 2 of the 3 tabs. I want to be able to refresh just the table view of the selected tab when the app wakes back up. I have tried using the notification center to tell my tab to refresh, but it makes the other tab crash because it is stealing the view from my progress hud. I will put some code here, so hopefully I can find a solution that will work for me.

Tab 1 ViewController

- (void)viewDidLoad {

    // becomeActive just calls viewDidAppear:
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(becomeActive:)
                                                 name:UIApplicationDidBecomeActiveNotification
                                               object:nil];

    [super viewDidLoad];

}

-(void)viewDidAppear:(BOOL)animated {
    HUD = [[MBProgressHUD alloc] initWithView:self.view];
    [self.view addSubview:HUD];

    HUD.delegate = self;
    HUD.labelText = @"Updating";
    HUD.detailsLabelText = @"Please Wait";

    [HUD showWhileExecuting:@selector(refreshData) onTarget:self withObject:nil animated:YES];

}

Tab 2 ViewController

- (void)viewDidLoad
{

    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
    self.navigationItem.title = [defaults valueForKey:@"companyName"];

    self.view.backgroundColor = background;

    tableView.backgroundColor = [UIColor clearColor];
    tableView.opaque = YES;
    tableView.separatorStyle = UITableViewCellSeparatorStyleNone;

    // becomeActive just calls viewDidAppear
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(becomeActive:)
                                                 name:UIApplicationDidBecomeActiveNotification
                                               object:nil];


    [super viewDidLoad];
    // Do any additional setup after loading the view from its nib.

    if (_refreshHeaderView == nil) {

        EGORefreshTableHeaderView *view = [[EGORefreshTableHeaderView alloc] initWithFrame:CGRectMake(0.0f, 0.0f - self.tableView.bounds.size.height, self.view.frame.size.width, self.tableView.bounds.size.height)];
        view.delegate = self;
        [self.tableView addSubview:view];
        _refreshHeaderView = view;
        [view release];

    }

    //  update the last update date
    [_refreshHeaderView refreshLastUpdatedDate];

}

-(void)viewDidAppear:(BOOL)animated {
    HUD = [[MBProgressHUD alloc] initWithView:self.view];
    [self.view addSubview:HUD];
    HUD.delegate = self;
    HUD.labelText = @"Updating";
    HUD.detailsLabelText = @"Please Wait";

    [HUD showWhileExecuting:@selector(updateBoard) onTarget:self withObject:nil animated:YES];

    //  update the last update date
    [_refreshHeaderView refreshLastUpdatedDate];

}

With this setup, my application will refresh tab 2 just fine, assuming that tab 2 was the last tab open before you closed the application. If I switch to tab 1 when I close, upon restarting the app, the notification calls tab 2 first and steals the view out from under my progress hud, so when I try to call the viewDidAppear method, the view is null and the app crashes. I either need to figure out how to implement the notification center better so it doesn't crash the other tab, or a better way overall to just refresh when the app becomes active. Looking forward to a good answer. Thanks in advance.

EDIT When I run with this setup, it aborts inside the MBProgressHUD

- (id)initWithView:(UIView *)view {
    // Let's check if the view is nil (this is a common error when using the windw initializer above)
    if (!view) {
        [NSException raise:@"MBProgressHUDViewIsNillException" 
                    format:@"The view used in the MBProgressHUD initializer is nil."]; // <-- Aborts on this line, so they know it can happen
    }
    id me = [self initWithFrame:view.bounds];
    // We need to take care of rotation ourselfs if we're adding the HUD to a window
    if ([view isKindOfClass:[UIWindow class]]) {
        [self setTransformForCurrentOrientation:NO];
    }
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(deviceOrientationDidChange:) 
                                                 name:UIDeviceOrientationDidChangeNotification object:nil];

    return me;
}
Was it helpful?

Solution 2

There really isn't much out there to help answer this question. @Learner gave me an idea that ultimately led to how I resolved this issue.

Since all of the logic I have works, the issue was to prevent the HUD from stealing the view from the other one since they both get called when they respond to the notification event. So in my -becomeActive event for both tabs, I added a check if the selectedIndex was a match for the current tab, if not, no refresh. Worked like a charm.

-(void)becomeActive:(NSNotification *)notification {
    // only respond if the selected tab is our current tab
    if (self.tabBarController.selectedIndex == 1) { // just set the number to your tab index
        [self viewDidAppear:YES];
    }

}

OTHER TIPS

Main problem here that notifications are received by all views, whether they will appear or not. Good practice would be to notify only those views which will appear in screen

you can use application delegate's (void)applicationWillEnterForeground:(UIApplication *)application method to handle change in application instead of notification.

  1. if problem is all about refreshing tab that is on screen then keeping track of change in tab in AppDelegate and using that when application enters foreground would be better idea over notification.

  2. Other option is to use viewWillAppear method in tabbarcontroller. When this method gets called, you can refresh current tab.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top