views:

306

answers:

2

Hello,

This is an Objective-C/iphone SDK question.

I have a dashboard view that is used to switch to different views in my application. Essentially the view has six buttons that shortcut to a different view.

Here is an example of the button event handling code:

- (IBAction)moreButtonPressed:(id)sender{
 // switch view here
 if(self._moreViewController == nil){
  MoreViewController *moreViewController = [[MoreViewController alloc] initWithNibName:@"MoreView" bundle:[NSBundle mainBundle]];
  self._moreViewController = moreViewController;
  [moreViewController release];
 }

 [self SwitchView:self._moreViewController];
}

I can duplicate this code for each button and change the appropriate classes (view controller classes)), but I would love a more elegant solution.

Does anyone have any idea of how to do this?

A: 

A simple improvement would be to set the tag property for each button when it is created then

- (IBAction)someButtonPressed:(id)sender{
 // switch view here

switch (sender.tag) {
case 0:
 if(self._moreViewController == nil){
  MoreViewController *moreViewController = [[MoreViewController alloc] initWithNibName:@"MoreView" bundle:[NSBundle mainBundle]];
  self._moreViewController = moreViewController;
  [moreViewController release];}
[self SwitchView:self._moreViewController];
break;
case 1:
 if(self._lessViewController == nil){
  MoreViewController *lessViewController = [[LessViewController alloc] initWithNibName:@"LessView" bundle:[NSBundle mainBundle]];
  self._lessViewController = lessViewController;
  [lessViewController release];}
[self SwitchView:self._lessViewController];
break;
 }

}

that way you only have one function. However it would be nice to not repeat the code in a case statement and just provide a parameter of the class to instantiate. Thats not something I have tried though.

Andiih
+4  A: 

First, move the name of the NIB into the ViewController class with code such as:

- (MoreViewController *)init
{
    self = [super initWithNibName:@"MoreView" bundle:nil];
    if (self != nil)
    {
    }
    return self;
}

This will make your view controllers self-contained so you can create them cleanly:

MoreViewController *moreViewController = [[MoreViewController alloc] init];

I recommend this approach no matter what else you do. Apple's sample code not withstanding, it is silly to put the name of the NIB in the caller. Why should every caller to a view controller need to know this internal implementation detail?

Next, remember that ObjC is a dynamic language. You can construct objects based on their Class name like this:

Class vcClass = NSClassFromString([self.classNameForSender objectForKey:sender])
UIViewController *vc = [[[vcClass alloc] init] autorelease];
[self switchToView:vc];

In the above, -classNameForSender is an NSDictionary that maps the button objects to the class name, but you can get these class names lots of other ways of course. Depending on the sender, you may be able to hang the class directly on the sender (though this is difficult with standard UIControls because they only have an integer tag to work with).

I haven't duplicated your storing the VC into an ivar. Do you really need this? If so, you can store it in a dictionary by name or you can store all the VCs in an NSMutableSet. But in most cases you really don't need this since most UI controllers (like NavController) will manage memory for you.

Another less dynamic approach is to create all the view controls at the beginning and put them in a dictionary, then you can just load them out of the dictionary based on the sender. This has the advantage of better compile-time checks, but can eat a lot more memory.

Rob Napier