问题
I am creating a turn based game and would like to know the correct process for my workflow. At present I have the following:
Home View Controller (which has a UITableView
)
Click on row from section 1 > Loads a UINavigationController
with path 1
Click on row from section 2 > Loads a UINavigationController
with path 2
As an example:
path 1 - play your turn
path 2 - guess your turn
Each path has around 4-5 UIViewControllers
loaded into the navigation controller.
Now I am at the stage where once path 2 is complete the user should then play their turn too (ie take path 2 then path 1).
What is the correct way to complete this? should I create a segue from the last controller in path 2 > leading to path 1. The issue is that path 2 has a UIViewController
that has a UIImageView
with a large image in and it would hang around in memory. Ideally it is cleared as such, before the user starts path 1 (after path 2 is complete)
回答1:
I have tried popToRootViewControllerAnimated
but its not working when we want movetopath2.
We can store some checkpoints in NSUserDefaults and then segue accordingly but that approach doesn't work in this case.
[self.navigationController popToRootViewControllerAnimated:YES];
Finally I have found solution as follows:
Start with below working code and change it as per your app logic

ViewController.m File
#pragma mark - UITableViewDelegate
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
if (indexPath.section == 0)
{
UIStoryboard *mainStoryBoard = [UIStoryboard storyboardWithName:@"Main" bundle:[NSBundle mainBundle]];
PathOneViewController *pathController = [mainStoryBoard instantiateViewControllerWithIdentifier:@"PathOneViewController"];
[self.navigationController pushViewController:pathController animated:YES];
}
else
{
UIStoryboard *mainStoryBoard = [UIStoryboard storyboardWithName:@"Main" bundle:[NSBundle mainBundle]];
PathTwoViewController *pathController = [mainStoryBoard instantiateViewControllerWithIdentifier:@"PathTwoViewController"];
[self.navigationController pushViewController:pathController animated:YES];
}
}
PathOneDetailViewController.m File
- (IBAction)actionMoveToPathTwo:(id)sender { // Move to path two
AppDelegate *appDelegateTemp = [[UIApplication sharedApplication]delegate];
UIViewController* rootController = [[UIStoryboard storyboardWithName:@"Main" bundle:[NSBundle mainBundle]] instantiateViewControllerWithIdentifier:@"PathTwoViewController"];
UINavigationController* navigation = [[UINavigationController alloc] initWithRootViewController:rootController];
appDelegateTemp.window.rootViewController = navigation;
}
- (IBAction)actionMoveToHome:(id)sender { // Move to table View
AppDelegate *appDelegateTemp = [[UIApplication sharedApplication]delegate];
UIViewController* rootController = [[UIStoryboard storyboardWithName:@"Main" bundle:[NSBundle mainBundle]] instantiateViewControllerWithIdentifier:@"ViewController"];
UINavigationController* navigation = [[UINavigationController alloc] initWithRootViewController:rootController];
appDelegateTemp.window.rootViewController = navigation;
}
PathTwoDetailViewController.m File
- (IBAction)actionMoveToHome:(id)sender { // Move to table View
AppDelegate *appDelegateTemp = [[UIApplication sharedApplication]delegate];
UIViewController* rootController = [[UIStoryboard storyboardWithName:@"Main" bundle:[NSBundle mainBundle]] instantiateViewControllerWithIdentifier:@"ViewController"];
UINavigationController* navigation = [[UINavigationController alloc] initWithRootViewController:rootController];
appDelegateTemp.window.rootViewController = navigation;
}
- (IBAction)actionMoveToPath1:(id)sender { // Move to path one
AppDelegate *appDelegateTemp = [[UIApplication sharedApplication]delegate];
UIViewController* rootController = [[UIStoryboard storyboardWithName:@"Main" bundle:[NSBundle mainBundle]] instantiateViewControllerWithIdentifier:@"PathOneViewController"];
UINavigationController* navigation = [[UINavigationController alloc] initWithRootViewController:rootController];
appDelegateTemp.window.rootViewController = navigation;
}
回答2:
Fire a notification from path 2
Be sure you subscribe to that notification in Home View Controller
In the notification handler method in Home View Controller, call the current navigation controller's
popToRootViewControllerAnimated:
.Manually call the segue to start path 1.
回答3:
The answer that worked for me was actually a much more simple approach. Adding a ViewController reference to the starting view controller for Path2. Then simply changing the view controllers in the UINavigationController
stack. As the navigation controller is not subclassed or doesn't need to be this works fine.
- (IBAction)completeButtonPressed:(id)sender {
NSLog(@"complete button pressed");
Path2ViewController *path2StartVC = [[UIStoryboard storyboardWithName:@"Main" bundle:[NSBundle mainBundle]] instantiateViewControllerWithIdentifier:@"Path21VC"];
[self.navigationController setViewControllers:[NSArray arrayWithObject:path2StartVC] animated:YES];
}
I will drop a sample project onto github for reference shortly.
回答4:
I would suggest you set your first controller as a UINavigationController and set its root control to the "Home View Controller" (UITableView). I'll call this the root navigation controller for now on. You then can keep the rest of the app's structure the same as you have it now, with one UINavigation controller for each route.
This would give you the advantage of being able to call the root navigation controller popToRootViewControllerAnimated:. Which in this case would be your "Home View Controller". There is one slight disadvantage to this and that is with your paths you can't just call popToRootViewControllerAnimated: on the current navigation controller when on a path. Since this would return you to the beginning of the path that you are on.
But this is easily fixed by keeping a reference to the root navigation controller. Which I would do by subclassing UINavigationController and just adding a property that stores a reference to the root view controller. The assignment would need to be done while the view controllers are transitioning from the table view to the navigation controllers that control one of your two paths. I think prepareForSegue:sender: would be your best bet to handle this.
As for your worry of the UIImageView staying in memory. You do not need to worry about it. When the view controller unloads it will unload the UIImageView as well. The only way you could keep a view controller from unloading is keeping a strong reference to it in another view controller. Which sometimes you want eg. parent / child relationship sometimes you don't eg. segue between view controllers. But passing properties between view controllers should be fine. For more info check out View Controller Guide
There are potentially a ton of different ways to solve this question. So, I would take my answer as a starting point and adapt it to what works best for the future of your app and your code style.
来源:https://stackoverflow.com/questions/21443803/storyboard-workflow-for-turn-based-game