Keeping a Reference to an iPhone UIViewController After Being Pushed
My question is this ... What are the pros and cons of keeping a reference to a UIViewController in the UIViewController's preceding UIViewController after it has been pushed onto the navigation controller and is this considered good programming practice. Here is code to demonstrate my question.
Keeping the Reference
Header
MainMenuViewController *mainMenuController;
@property (nonatomic, retain) MainMenuViewController *mainMenuController;
Main
if (self.mainMenuController == nil)
{
//Goto the next page
MainMenuViewController *controller = [[MainMenuViewController alloc] init];
self.mainMenuController = controller;
[controller release];
}
[self.navigationCon开发者_开发技巧troller pushViewController:mainMenuController animated:TRUE];
Not Keeping the Reference
MainMenuViewController *controller = [[MainMenuViewController alloc] init];
[self.navigationController pushViewController:controller animated:TRUE];
[controller release];
Saving a reference is more about your usage than anything else. If you are pushing up a view controller that you will be commonly using in the future than you will want to keep a reference to it. However if it is a one time use view than you may not want to keep it. Or you may want to keep it so you only have to load it once.
Alternatively if you have an xib load the view for you then you will maintain a reference to the view unless you want to reload from the xib every time you want to use it.
For instance, If you are loading a view with a web view on it into the navigation controller. You may want to load it. set the url so it will load the page. And then hand it off to the navigation controller as you let the user navigate the web from there.
If however you are pushing your home page onto the stack and they have the possibility of sending commands back to that page from other pages. You will want to keep a hold of the View so that you can let the actions they do in subsequent pages trickle back down to the home page through protocols, the Application Delegate or whatever other means of reference you have at your disposal.
Either way you will have to make that distinction. Just keep in mind that holding onto too much memory will give you a warning, at that time you will need to prioritize what you want to keep around and what you can get rid of. This is where application design gets fun :)
Hope that helps. And Good Luck
It's hard to say without knowing more about your implementation.
If the retained view controller contains a bunch of heavy, non-view, dependent objects (data sources, perhaps), you could be using a meaty chunk of memory for nothing if the user doesn't do anything to invoke that view again after it's first loaded.
On the other hand, if loading the view and/or controller is expensive for some reason, and you're certain that the user will frequently access it, holding onto the view controller may be a good idea and make your application more responsive.
If you do choose to hold onto the view controller, be certain to be responsive to memory warnings and dump the controller when necessary.
btw, if you'd like to save a few keystrokes and make your condition immediately clear when reading your code later, you can do this to test for nil-ness:
if (!self.mainMenuController)
Given that the class in your example is called MainMenuViewController
, I'd say that the right thing in this instance is to keep the object alive, because it sounds like the sort of thing the user will keep coming back to. View controllers are generally lightweight, and shed offscreen views when memory gets low, re-creating them when they become visible again. You should get in the habit of setting up anything (not just views) which can be treated similarly in -viewDidLoad
and tearing it down in -viewDidUnload
.
If you were pushing a view controller as a result of selecting from a dynamic list, such as the Mail app does when you select a message, you probably wouldn't bother to keep a reference, although you might want to keep one to the most recent view controller so as to be more forgiving if the user mistakenly presses the back button by returning to the exact same state in the detail view as you previously were.
It depends on requirement of the application. Let's suppose you want to add or remove something to main controller after before pushing on navigation stack then we can already allocate the mainController and do whatever we want to do with that. I tell with an example what I do in my case is I need to show some data on tableView let say tableView is in viewController2 and I'm getting that table's data source on viewController1 so before I push the viewController2 I initialize the viewController2 keep it's reference and assign data source to the viewController2 and reload table. This is my reason to keep the reference.
As you pointed out you keep reference. As the word describes it, it is a one way relation between a creator object and the object being created. So the need to keep a relation is to be able to comunicate with the created object. If you don't have a reference you cant talk to it. So whenever you design something that will need to talk to your newly created object you need to keep a reference to it.
You've created undesirable coupling between the two view controllers. You're writing in-stone that MainViewController will always have a parent of type MainViewController. This is a needless restriction. In the future, you may wish to instantiate and load MainViewController directly from another view controller.
In general, when using UINavigationController, each view controller should not make assumptions about the type of its parent view controller.
A better approach uses the delegate/protocol pattern.
Header
@protocol MainViewControllerProtocol;
@interface MainViewController : UIViewController {
id <MainViewControllerProtocol> delegate
}
@property (nonatomic, assign) id <MainViewControllerProtocol> delegate;
@end
@protocol MainViewControllerProtocol <NSObject>
- (void)somethingHappened;
@end
精彩评论