Reputation: 27113
I have UIViewController
that contain another two UIViewControllers
as properties.
MenuViewController contains:
@property (nonatomic, strong) TeamsViewController *teamsViewController;
@property (nonatomic, strong) ResultsViewController *resultsViewController;
The MenuViewController contains table view and when user tap on the cell "show teams" I need to initialize teamsViewController and show teamsViewController view. The same thing when user press on the cell "show results" but in this case I need to show resultsViewController view.
So, I usually do this is in one way initialize controllers when cell is pressed and call addSubview method that will add controllers view. But I think it is not good solution am I right?
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if (_teamsViewController) _teamsViewController = nil;
_teamsViewController = [TeamsViewController new]
[self.view addSubView:_teamsViewController];
}
Is the method above ok?
There is my hierarchy of view each of them managed by its own controller. So the white you managed by MenuViewController and the gray view managed by ResultViewController and blue view managed by TeamsViewController.
As I said before when I tap on appropriate cell in menu view controller I need to show teams or results. But each of this view has another view controller. Or maybe I confused about view controller paradigm? Maybe TeamsViewController should be a TeamsView and ResultsViewController should be ResultsView ? So both view controllers has the table as well that managed in their controllers. So i don't think it has to be a UIView instead of UIViewController.
Upvotes: 0
Views: 96
Reputation: 1876
I think your best bet is to set this up as a UINavigationController. UINavigationController inherits from UIViewController so you aren't losing any functionality this way. You could then set it up like this:
//MenuViewController.h
@interface MenuViewController : UINavigationController
@property (nonatomic, strong) TeamsViewController *teamsViewController;
@property (nonatomic, strong) ResultsViewController *resultsViewController;
//Insert other properties and methods....
@end
and in the method called when someone clicks on a cell, you would simply do this:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if (!self.teamsViewController) {
self.teamsViewController = [[UIViewController alloc] initWithNibName:@"nibName" bundle:nil];
}
[self pushViewController:self.teamsViewController animated:YES];
}
Now, you have two view controllers, so you have to tell your method above which one to push onto the stack. If the rows are fixed, you can simply decide which one to show based on indexPath
but if it's more dynamic (i.e. tableview is created from a database) then you'll need to have some more complex logic code here.
Without making too many assumptions, but to give you some general guidance, when you create a cell you would generally set some sort of flag on it to indicate what type it is. This can be done with an NS_ENUM or with a simple BOOL if you only have two states (I prefer to use ENUMs whenever possible as they are much more descriptive). You would then check for the existence of that flag in the tableView:didSelectRowAtIndexPath:
method, pushing the corresponding view onto the navigation stack. Something like this (this is not literal code, but shown just to give you an idea:
// This code assumes in the method tableView:cellForRowAtIndexPath:
// you have set the tag property to '1' if a TeamsViewController is
// needed or '2' if a ResultsViewController is needed when that cell
// is pressed.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
self.teamsViewController = self.teamsViewController ? self.teamsViewController : [[UIViewController alloc] initWithNibName:@"TeamsViewController" bundle:nil];
self.resultsViewController = self.resultsViewController ? self.resultsViewController : [[UIViewController alloc] initWithNibName:@"ResultsViewController" bundle:nil];
switch ([[tableView cellForRowAtIndexPath:indexPath] tag]) {
case 1:
[self pushViewController:self.teamsViewController animated:YES];
break;
case 2:
[self pushViewController:self.resultsViewController animated:YES];
break;
default:
break;
}
}
You would still need to do your initialization in your teams or results view controller to show the view but this should steer you in the general direction.
Upvotes: 1
Reputation: 11598
I'd recommend using Storyboards and making sure to have a "Storyboard ID" for each of them. That way, it becomes a bit easier to push various UIViewController
instances, as needed. This is my typical pattern:
UIViewController *vc = [self.storyboard
instantiateViewControllerWithIdentifier:@"selected identifier"];
[self.navigationController pushViewController:vc animated:YES];
Also, unless you need to set properties in the child view controller, there's no need to have a property reference to it. Further, this answer assumes that you're using a UINavigationController
, with your MenuViewController
set as the rootViewController
. You can either set this up in IB with a Storyboard (easy and probably the preferred way), or in code like this:
MenuViewController *vc = [[UIViewController alloc] initWithNibName:@""
bundle:nil];
UINavigationController *navVc = [[UINavigationController alloc]
initWithRootViewController:vc];
Upvotes: 1