pushplay

interactive · design · studio


< Back to Main

Framework for having Multiple Views in an iPhone app

May 6, 2009
|

I needed to create an application base with multiple view controllers, and an easy method for switching between them. I came up with a solution that passes messages via the App Delegate, and has a parent View Controller that manages the sub-views.

flowchart representing a parent app controller and view controller with multiple subviews

The following code is the App Delegate:

MultiviewAppDelegate.h

#import <UIKit/UIKit.h>
 
@class MultiviewViewController;
 
@interface MultiviewAppDelegate : NSObject <UIApplicationDelegate> {
       UIWindow *window;
       MultiviewViewController *viewController;
}
 
@property (nonatomic, retain) IBOutlet UIWindow *window;
@property (nonatomic, retain) IBOutlet MultiviewViewController *viewController;
 
-(void) displayView:(int)intNewView;
 
@end

MultiviewAppDelegate.m

#import "MultiviewAppDelegate.h"
#import "MultiviewViewController.h"
 
@implementation MultiviewAppDelegate
 
@synthesize window;
@synthesize viewController;
 
-(void) displayView:(int)intNewView {
       [viewController displayView:intNewView];
}
 
- (void)applicationDidFinishLaunching:(UIApplication *)application {
       [window addSubview:viewController.view];
       [window makeKeyAndVisible];
}
 
 
- (void)dealloc {
       [viewController release];
       [window release];
       [super dealloc];
}
 
 
@end

Pretty basic stuff (almost exactly the default for the AppDelegate template). The only addition is the displayView function, which passes a message to the parent View Controller.

MultiviewViewController.h

#import <UIKit/UIKit.h>
 
@interface MultiviewViewController : UIViewController {
}
 
- (void) displayView:(int)intNewView;
 
@end

This has an internal displayView function which is called by the AppDelegate.

MultiviewViewController.m

#import "MultiviewViewController.h"
// you have to import the header files for
// any views that this parent controls
#import "View01.h"
#import "View02.h"
 
@implementation MultiviewViewController
 
UIViewController  *currentView;
 
- (void) displayView:(int)intNewView {
       NSLog(@"%i", intNewView);
       [currentView.view removeFromSuperview];
       [currentView release];
       switch (intNewView) {
               case 1:
                       currentView = [[View01 alloc] init];
                       break;
               case 2:
                       currentView = [[View02 alloc] init];
                       break;
       }
 
       [self.view addSubview:currentView.view];
}
 
 
- (void)viewDidLoad {
       // display Welcome screen
       currentView = [[View01 alloc] init];
       [self.view addSubview:currentView.view];
 
   [super viewDidLoad];
}
 
- (void)didReceiveMemoryWarning {
   [super didReceiveMemoryWarning]; // Releases the view if it
doesn't have a superview
   // Release anything that's not essential, such as cached data
}
 
 
- (void)dealloc {
       [currentView release];
   [super dealloc];
}
 
@end

Now we just have to have multiple sub-views.

View01.h

#import <UIKit/UIKit.h>
 
@interface View01 : UIViewController {
 
}
 
@end

View01.m

#import "View01.h"
#import "MultiviewAppDelegate.h"
 
@implementation View01
 
- (void)goToTwo {
       MultiviewAppDelegate *appDelegate = [[UIApplication
sharedApplication] delegate];
       [appDelegate displayView:2];
}
 
- (void)viewDidLoad {
       NSLog(@"load01");
 
       UIButton *btnOne = [UIButton buttonWithType:UIButtonTypeRoundedRect];
       btnOne.frame = CGRectMake(40, 40, 240, 30);
       [btnOne setTitle:@"One!" forState:UIControlStateNormal];
       [btnOne addTarget:self action:@selector(goToTwo)
forControlEvents:UIControlEventTouchUpInside];
       [self.view addSubview:btnOne];
 
   [super viewDidLoad];
}
 
- (void)didReceiveMemoryWarning {
   [super didReceiveMemoryWarning]; // Releases the view if it
doesn't have a superview
   // Release anything that's not essential, such as cached data
}
 
 
- (void)dealloc {
       NSLog(@"dealloc01");
   [super dealloc];
}
 
 
@end

The second view looks just like the first, but goes to "one" instead of two.

View02.h

#import <UIKit/UIKit.h>
 
@interface View02 : UIViewController {
 
}
 
@end

View02.m

#import "View02.h"
#import "MultiviewAppDelegate.h"
 
@implementation View02
 
- (void)goToOne {
       MultiviewAppDelegate *appDelegate = [[UIApplication
sharedApplication] delegate];
       [appDelegate displayView:1];
}
 
- (void)viewDidLoad {
       NSLog(@"load02");
 
       UIButton *btnTwo = [UIButton buttonWithType:UIButtonTypeRoundedRect];
       btnTwo.frame = CGRectMake(40, 40, 240, 30);
       [btnTwo setTitle:@"Two!" forState:UIControlStateNormal];
       [btnTwo addTarget:self action:@selector(goToOne)
forControlEvents:UIControlEventTouchUpInside];
       [self.view addSubview:btnTwo];
 
   [super viewDidLoad];
}
 
- (void)didReceiveMemoryWarning {
   [super didReceiveMemoryWarning]; // Releases the view if it
doesn't have a superview
   // Release anything that's not essential, such as cached data
}
 
 
- (void)dealloc {
       NSLog(@"dealloc02");
   [super dealloc];
}
 
 
@end

And that's it! It seems like a lot, but it's a basic framework that makes it easy to add in new views and navigate between them.

I created this to help me go between multiple screens built by different developers that weren't working in the same environment. It makes it easy to add the .m and .h file of a View Controller, and then with some minor changes, be able to insert it into the navigation flow of any application.

One caveat: if you have a timer, you need to invalidate it before you call [appDelegate displayview:]. I've also been making it a habit to set my objAccelerator.delegate = nil in the dealloc function of each View Controller.

You must also have good memory management practices (release everything you alloc!), because the dealloc is not just called when the program terminates -- it's called every time you switch views.

Download the source files here!

21 Comments

06 May
2009
Lee Armstrong
Great article! If I was to start afresh and implement that code would I start with a Window application? And then add the views and corresponding xib files?
07 May
2009
Jeffrey Berthiaume
Actually, I started from a View-based Application (that I called "Multiview")... That way, MultiviewAppDelegate.h, MultiviewAppDelegate.m, MultiviewViewController.h, and MultiviewViewController.m are created automatically. I don't ever use xib files or Interface Builder -- I tend to prefer doing everything in code...
27 Jun
2009
Jim
I know this was a couple of months back but I'm just starting with iPhone development and was wondering if this method supported animation between views/controllers and if after OS 3.0 anything in the framework has since made working with multiple views/controllers easier?
29 Jun
2009
Jeffrey Berthiaume
No, I'm not transitioning between views using this framework. Also, as far as I know, OS 3.0 doesn't do anything different (API-wise) for managing views...
21 Jul
2009
don
Hi, Can you please tell how to mix the view types as well?! like the view 1 being core graphics using some nib, view 2 being openGL es view I am trying to put in opengl es in addmusic sample code, but am failing to figure it out. please help
23 Jul
2009
prasad
This is the best article I ever found.. good design, easily scalable and faster.. And I think the second "MultiviewAppDelegate.h" should be "MultiviewAppDelegate.m" in the code section.. :-)
23 Jul
2009
Adam
Hey, this code was really helpful. Thank you! Also I have the same question that Don asked. I'm trying to figure out how to load in a UIView and a view using openGL. Its quite tricky, if you know of a good way please let me know! Thank you.
23 Jul
2009
Adam
Don, I figured out what you wanted to know. Add EAGLView.h and m to your project. Then in one of your views view did load put in:
EAGLView *background = [[EAGLView alloc]
    initWithFrame:CGRectMake(0.0f, -20.0f, 320.0f, 470.0f)];
 
  [background startAnimation];
  background.animationInterval = 1.0 / 60.0;
  [self.view addSubview:background];
  [background release];
    
  [super viewDidLoad];
Also add #import "EAGLView.h" to the top of the file. Then in EAGLView.m replace init with coder for this function.
- (id) initWithFrame:(CGRect)frame 
{
  if((self = [super initWithFrame:frame])) {
    CAEAGLLayer* eaglLayer = (CAEAGLLayer*)[self layer];
        
    eaglLayer.drawableProperties = [NSDictionary dictionaryWithObjectsAndKeys:
      [NSNumber numberWithBool:YES],
      kEAGLDrawablePropertyRetainedBacking,
      kEAGLColorFormatRGBA8,
      kEAGLDrawablePropertyColorFormat, nil];
 
    context = [[EAGLContext alloc]
      initWithAPI:kEAGLRenderingAPIOpenGLES1];
 
    if(context == nil) {
      [self release];
      return nil;
    }
  }
    
  return self;
}
Give it a try and see if it works
06 Aug
2009
David Sielert
Excellent document exactly what I was looking for. Wish there were a way to steer away from using the integer associations with the views ..
24 Sep
2009
Brent Chapman
Do you know if there is any way to add a uitabviewcontroller to one of the sub views? I am having trouble finding a way to do this.
26 Sep
2009
mauricio giraldo
This is just what I was looking for. Thanks.

How would you manage this with NIBs. I already got everything set up with NIBs and they stay in memory throughout the whole app lifetime (consuming resources). dealloc/viewDidUnload never fires.
27 Sep
2009
mauricio giraldo
I have managed to make dealloc fire but the nib is still in memory. I have put a more detailed question (along with my implementation of your framework) here:

http://stackoverflow.com/questions/1482934/iphone-app-with-multiple-views-subviews-memory-is-not-being-deallocated
09 Oct
2009
mauricio giraldo
Hi

I did a NIB-based version of your framework. You can download it here: http://www.mauriciogiraldo.com/blog/2009/10/09/multiples-views-no-jerarquicas-en-iphone/
16 Oct
2009
Mike
Looking at Adams comments regarding the EAGLView.h stuff. Has someone actually taken the OpenGLES Template and modified it so this works?

Several questions come to mind - are these change based on the Template? Will the work with the new 3.0 SDK?

I would love to see the full sample code of the 3.x sdk OpenGLES template modifed to work with this code.
24 Nov
2009
Gary
This is an excellent, and a very useful, tutorial. Thank you very much for putting this together.

I have managed to include the multiviewcontroller into a Tableview application, and to then get the multiview window to be spawned from a tableview didSelectRowAtIndexPath event in the RootViewController, but I am seeing a warning message telling me that the AppDelegate might not respond to the displayView method, and of course this does not respond.

How do I hook the appDelegate back to the actual delegate?

Alternatively, how would one hand code a TableView into this application?

Thank you in advance for your assistance.
03 Jan
2010
Arseniy Banayev
This is probably the single most useful article I've found on iPhone dev. The language is clear, the code is even clearer, and it works like a charm. Also, expansion is easy, so this template is wonderful. I suggest making a downloadable Xcode template with heavy comments or something, so the user knows what to change and how to add more views.

Thank you so much!
04 Jan
2010
Hardik
Hello Sir,
Really a nice document.
But can you help me with this.
I have an application developed in OPENGL ES.
I want to use UIVEWCONTROLLER.Can you help me this
14 Jan
2010
shubham
I wonder if you can have a EAGLview as one of the views. I see Adam above has given an idea, but how about unloading and reloading again and again...

a sample code of the same will be wonderful!
04 Feb
2010
Gubb
Wow, thanks! This saved my final project from becoming a complete failure. Awesome!
08 Feb
2010
Yohannes Woldemariam
I learned a lot from this program. Thanks you very much, but how do you include a view with hierarchical information, (tableview and navigation controller)


08 Feb
2010
Yohannes Woldemariam
I learned a lot from this program. Thanks you very much, but how do you include a view with hierarchical information, (tableview and navigation controller)


Submit a Comment:

Your Name:
Email Address:
Comments:
Enter what you see: Verification Image