royherma
royherma

Reputation: 4203

Pushing view controller within block not working

What is the correct way to fire methods within a completion block (if this is even recommended)? Right now, I have an IBAction that calls a method that downloads information with a completion block signifying if the info was retrieved successfully or not. If it was, I want to push a view controller that will display that information, but at the moment, nothing is happening. I'm guessing it has something to do with main thread, gcd, etc...

__weak YTTMSetupViewController *weakSelf = self;
    [mc downloadJson:^(BOOL success) {
            if(success){
                NSLog(@"sucess. metric count - %i",(int)mc.collection.count);

                //info was downloaded. Push new view controller with info
                YTTMMetricTableViewController *mtvc = [self.storyboard instantiateViewControllerWithIdentifier:@"YTTMMetricTableViewController"];
                mtvc.group = (WAGroup*)[[WAMetricCollection sharedInstance].collection lastObject];
                mtvc.hidesBottomBarWhenPushed = YES;
                [weakSelf.navigationController pushViewController:mtvc animated:YES];
            }
            else{
                NSLog(@"failure");
                //display failure UI
            }
            NSLog(@"end of downloading");
            [HUD dismissAfterDelay:0.5f animated:YES];
        }];

Upvotes: 1

Views: 611

Answers (3)

Darren
Darren

Reputation: 1427

You could simply try wrapping the call with a dispatch_asynch block...

__weak YTTMSetupViewController *weakSelf = self;
    [mc downloadJson:^(BOOL success) {
        if(success){
            NSLog(@"sucess. metric count - %i",(int)mc.collection.count);

            dispatch_async(dispatch_get_main_queue(), ^{
                //info was downloaded. Push new view controller with info
                YTTMMetricTableViewController *mtvc = [self.storyboard instantiateViewControllerWithIdentifier:@"YTTMMetricTableViewController"];
                mtvc.group = (WAGroup*)[[WAMetricCollection sharedInstance].collection lastObject];
                mtvc.hidesBottomBarWhenPushed = YES;
                [weakSelf.navigationController pushViewController:mtvc animated:YES];
            });
        }
        else{
            NSLog(@"failure");
            //display failure UI
        }
        NSLog(@"end of downloading");
        [HUD dismissAfterDelay:0.5f animated:YES];
    }];

Upvotes: 1

Morgan Chen
Morgan Chen

Reputation: 1217

All UI updates must be performed on the main thread. Personally I prefer to do this through GCD as it produces more readable code than performSelectorOnMainThread. However, there's nothing wrong with performSelectorOnMainThread aside from personal preference in the case of calling a single UI update on the main thread following the execution of some completion block. Do note that, whichever one you choose, you should be consistent with what you use to guarantee that blocks are enqueued in the order you specified.

Working code aside, however, the convention Apple's frameworks seem to use is to perform all completion blocks on the main thread unless a queue is specified as a method parameter, in which case the completion block should be performed on that queue. So in this case I would recommend you edit your download handler class's downloadJson method to automatically perform the completion block on the main queue.

Upvotes: 0

royherma
royherma

Reputation: 4203

Not sure if this is the right way to do it, but it worked.

I added a method that will push the vc on the main thread as so:

        [weakSelf performSelectorOnMainThread:@selector(pushDetail) withObject:nil waitUntilDone:YES];

Completed Code:

__weak YTTMSetupViewController *weakSelf = self;
    [mc downloadJson:^(BOOL success) {
            if(success){
                NSLog(@"sucess. metric count - %i",(int)mc.collection.count);

                //info was downloaded. Push new view controller with info
                [weakSelf performSelectorOnMainThread:@selector(pushDetail) withObject:nil waitUntilDone:YES];
            }
            else{
                NSLog(@"failure");
                //display failure UI
            }
            NSLog(@"end of downloading");            
        }];

}

-(void)pushDetail{
    __weak YTTMSetupViewController *weakSelf = self;
    YTTMMetricTableViewController *mtvc = [self.storyboard instantiateViewControllerWithIdentifier:@"YTTMMetricTableViewController"];
    mtvc.group = (WAGroup*)[[WAMetricCollection sharedInstance].collection lastObject];
    mtvc.hidesBottomBarWhenPushed = YES;
    [weakSelf.navigationController pushViewController:mtvc animated:YES];

}

Upvotes: 1

Related Questions