Skip to content

Instantly share code, notes, and snippets.

@fpillet
Created October 22, 2014 16:35
Show Gist options
  • Save fpillet/1e76066643f42681f0fc to your computer and use it in GitHub Desktop.
Save fpillet/1e76066643f42681f0fc to your computer and use it in GitHub Desktop.
Chaining VCs from ViewModels
- (void)pushViewModel:(BaseViewModel *)nextViewModel
{
NSString *from = [self standardNameFromViewModel:_currentViewController.viewModel];
NSString *to = [self standardNameFromViewModel:nextViewModel];
// We are going to try and find a segue to go to the next viewModel. The way segues are named
// in our storyboard should be: FromModel::ToModel
// 1. try Segue method. For example, a segue going from WelcomeViewController to LoginViewController would be named "Welcome::Login"
// 2. If a segue is not found, try to instantiate the view controller and push it directly. We look up the view controller by its stripped model name (i.e. "WelcomeViewModel" -> "Welcome")
// 3. If the view controller is not found in the storyboard, try a XIB with the stripped model name.
@try
{
// Hook into currentViewController's -prepareForSegue method to automatically bind view model to instantiated view controller
UIViewController *currentVC = (UIViewController *)_currentViewController;
if (currentVC)
{
// this Aspect hook will execute ONCE on the target view controller and bind the view model
// to the UIViewController that was instantiated from a segue
[currentVC aspect_hookSelector:@selector(prepareForSegue:sender:)
withOptions:AspectPositionAfter | AspectOptionAutomaticRemoval
usingBlock:^(id<AspectInfo> ai, UIStoryboardSegue *segue, id sender) {
LOG_MODEL(0, @"prepareForSegue from %@ to %@", segue.sourceViewController, segue.destinationViewController);
id viewController = segue.destinationViewController;
if ([viewController isKindOfClass:[MainTabBarViewController class]])
[self configureTabBarController:(MainTabBarViewController *) viewController withViewModel:nextViewModel];
else
[self configureNextController:(BaseViewController *) viewController withViewModel:nextViewModel];
} error:NULL];
}
[currentVC performSegueWithIdentifier:[NSString stringWithFormat:@"%@::%@", from, to] sender:self];
}
@catch (NSException *exception)
{
// Segue not found, try locating the view controller in the storyboard
UIViewController *viewController = [self.mainStoryboard instantiateViewControllerWithIdentifier:to];
if (viewController == nil)
viewController = [[UIViewController alloc] initWithNibName:to bundle:nil];
if ([viewController isKindOfClass:[MainTabBarViewController class]])
[self configureTabBarController:(MainTabBarViewController *) viewController withViewModel:nextViewModel];
else
[self configureNextController:(id<AppViewController>)viewController withViewModel:nextViewModel];
// Since there is no segue, we will push from current navigation controller
[((UIViewController *)_currentViewController).navigationController pushViewController:viewController animated:YES];
}
}
@fpillet
Copy link
Author

fpillet commented Feb 19, 2015

This code uses the Aspects library by Peter Steinberger https://github.com/steipete/Aspects to automatically configure storyboard segues in MVVM applications when transitioning from one view controller to the other.

To identify the proper segue, we use the source and destination view controller classes and derive a standard format name for the segue. For example, transitioning from a LoginViewController to a MainViewController would look up a segue named "Login::Main" then automagically configure and run it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment