How to use multiple custom View Controllers with a Navigation Controller? - iphone

Basically, I have two view controllers inside the MainWindow.xib that can be viewed by clicking the Bar Button in my Navigation Controller. I wanted those two view controllers to be separated from the MainWindow.xib with their own header, implementation and xib files and still make Navigation Controller inside of MainWindow.xib work in them.
To better understand it, please see the codes below:
Thanks a lot!
TestAppDelegate.h
#import <UIKit/UIKit.h>
#interface TestAppDelegate : NSObject <UIApplicationDelegate>
{
//Navigation Controller
IBOutlet UINavigationController *navigationController;
//View Controllers
UIViewController *viewController;
UIViewController *viewController2;
UIViewController *viewController3;
}
#property (nonatomic, retain) IBOutlet UIWindow *window;
//Navigation Controller
#property (nonatomic, retain) IBOutlet UINavigationController *navigationController;
//View Controllers
#property (nonatomic, retain) IBOutlet UIViewController *viewController;
#property (nonatomic, retain) IBOutlet UIViewController *viewController2;
#property (nonatomic, retain) IBOutlet UIViewController *viewController3;
- (IBAction)next;
- (IBAction)next2;
#end
TestAppDelegate.m
#import "TestAppDelegate.h"
#implementation TestAppDelegate
#synthesize window = _window;
//Navigation Controller
#synthesize navigationController;
//View Controllers
#synthesize viewController;
#synthesize viewController2;
#synthesize viewController3;
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// Override point for customization after application launch.
//Navigation Controller
[self.window addSubview:[navigationController view]];
[self.window makeKeyAndVisible];
return YES;
}
- (void)applicationWillResignActive:(UIApplication *)application
{
}
- (void)applicationDidEnterBackground:(UIApplication *)application
{
}
- (void)applicationWillEnterForeground:(UIApplication *)application
{
}
- (void)applicationDidBecomeActive:(UIApplication *)application
{
}
- (void)applicationWillTerminate:(UIApplication *)application
{
}
- (void)dealloc
{
[viewController release];
[viewController2 release];
[viewController3 release];
[navigationController release];
[_window release];
[super dealloc];
}
- (IBAction)next {
[navigationController pushViewController:viewController2 animated:YES];
}
- (IBAction)next2 {
[navigationController pushViewController:viewController3 animated:YES];
}
#end
Inside MainWindow.xib:
http://i52.tinypic.com/10xa45f.png

I normally don't touch MainWindow.xib. I suggest the following:
Create a MainController which will be your MainView that subclass UIViewController by going to File > New > New File. That will create a .h/.m and nib file for each ViewController. There add whatever UI you want for your app. For Example, add two buttons and wire those buttons to IBActions in your MainController. This should be declared and implemented in your MainController.{h/m}, respectively.
After that create another two ViewControllers, the same way.
The body of those IBActions should create an instance of the your ViewControllers and then push them.
It would look something like this:
YourViewController *yvc = [[YourViewController alloc] init];
[self.navigationController pushViewController:yvc animated:YES];
[yvc release];
Finally, you have to push the MainController in your AppDelegate and add your NavigationController to the view.
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
MainViewController *mvc = [[MainViewController alloc] init];
UINavigationController *unvc = [[UINavigationController alloc] init];
[unvc pushViewController:mvc animated:NO];
[mvc release];
[self.window addSubview:unvc.view];
[self.window makeKeyAndVisible];
return YES;
}

Set the "class" property in Interface Builder (third tab in the inspector, "Custom Class") to the name of the custom class you're planning to use, and then put the name of the .xib file you want to load from in the "NIB Name" (fourth tab).
The code you're using to push the viewController is alright. Make sure to never accidentaly dealloc any of the two UIViewController.
Speaking of which, keep in mind that this approach is keeping the ViewControllers always in memory, even when not in use. Another approach is to completely remove the IBOutlets for the two ViewControllers, and do something like:
- (IBAction)next
{
MyCustomViewController *customViewController = [[MyCustomViewController alloc] initWithNibName:<#NibName or nil#> bundle:[NSBundle mainBundle]];
[navigationController pushViewController:customViewController animated:YES];
[customViewController release];
}
This creates the object when needed (If I remember right, the UI elements from the xib are cached somewhere, so that may be irrelevant[citation needed]). Just something to keep in mind, depending on the frequency of use of your two ViewControllers.

Related

Adding a TableViewController to an existing project

I have an existing TableViewController as follows
// TableViewController.h
#interface TableViewController : UITableViewController { NSArray *dataArray; }
#property (nonatomic, retain) NSArray *dataArray;
And a navAppDelegate - to be specific:
// navAppDelegate.h
#import <UIKit/UIKit.h>
#interface navwAppDelegate : NSObject
<UIApplicationDelegate, UINavigationControllerDelegate> {
UIWindow *window;
IBOutlet UINavigationController *navigationController;}
#property (nonatomic, retain) IBOutlet UIWindow *window;
#property (nonatomic, retain) UINavigationController *navigationController;
// navAppDelegate.m
#import "navAppDelegate.h"
#implementation navigationtableviewAppDelegate
#synthesize window, navigationController;
- (void)applicationDidFinishLaunching:(UIApplication *)application
{
[window makeKeyAndVisible];
[window addSubview:[navigationController view]];
}
Now, I simply added the files to an existing project, except I put the content of (void)applicationDidFinishLaunching{} in a (void)viewDidLoad{} since it's a view from now on and not a window (right?). It doesn't work and my guess is that I have to change all the window calls from above to a view? What am I making here fundamentally wrong?
I'm making a call from
// StartOffHere.m
- (void)LetsGoButtonTouched {
navAppDelegate *newview = [[navAppDelegate alloc] initWithNibName:nil bundle:nil]; // I get a SIGABRT here
[[self navigationController] pushViewController: newview animated: YES];
}
- (void)LetsGoButtonTouched {
TableViewController *tableViewController = [[TableViewController alloc] init];
[[self navigationController] pushViewController:tableViewController animated: YES];
}
Try that. Is that what you wanted to happen?
If so, what I have done is created a new instance of your table view controller and pushed that. In your original code, you were trying to push on the app delegate which cannot be done; the app delegate is not a view controller. TableViewController, your subclass of UITableViewController, is though, so you can use this for the pushViewController: method - and the table view will appear on screen.
Thanks Benjamin. Excellent. But it didn't work quite that way though - after two hard days I managed it to run. For those who are interesed, here's what I did:
If you want to add an existing TableViewController with a NavigationController you'll only need the TableViewController and the DetailViewController files. Forget the AppDelegate.
Do twice new file -> Subclass and copy your existing code into identical TableViewController .h/.m/.xib - and DetailViewController .h/.m/.xib respectively.
When you make the method call you have to integrate both the TableViewController and the NavigationController - like this:
- (void)LetsGoButtonTouched {
TableViewController *tvc = [[[TableViewController alloc] init] autorelease];
UINavigationController *navigationController = [[[UINavigationController alloc] initWithRootViewController:tvc]autorelease];
[self presentModalViewController:navigationController animated:YES];
By the way, this question gave me the hint:
Add a UINavigationBar to a UITableViewController without a UINavigationController

Go to another view (UIViewController) from within UIViewController

A newbie Objective C question. Im trying to programmaticly change view from another view. But I only succeed in activating the tab button in the tabbarcontroller.
In my ViewDidLoad I have a condition that if thats not met, load the second view instead.
Is there any kind soul that can help out a Objective-C beginner? I have googled and search stackoverflow for the answer but with no luck.
FirstViewController.h
#interface FirstViewController : UIViewController {
some variables
}
some #properties
FirstViewController.m
#import "FirstViewController.h"
#implementation FirstViewController
- (void)viewDidLoad
{
if(condition is met) {
[self.tabBarController setSelectedIndex:1];
}
}
In my AppDelegate.h
#import <UIKit/UIKit.h>
#interface otpAppDelegate : NSObject <UIApplicationDelegate, UITabBarControllerDelegate> {
UIWindow *window;
UITabBarController *tabBarController;
}
#property (nonatomic, retain) IBOutlet UIWindow *window;
#property (nonatomic, retain) IBOutlet UITabBarController *tabBarController;
#end
AppDelegate.m
#implementation otpAppDelegate
#synthesize window;
#synthesize tabBarController;
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
[self.window addSubview:tabBarController.view];
[self.window makeKeyAndVisible];
tabBarController = [[UITabBarController alloc] init];
[tabBarController setDelegate:self];
return YES;
}
Edit!
I found a solution to my problem.
int selectedindex = 1;
self.tabBarController.selectedIndex = selectedindex;
UIViewController *tempvc = [[self.tabBarController viewControllers] objectAtIndex:selectedindex];
[self.view removeFromSuperview];
[self.view addSubview:tempvc.view];
Did the trick.
Try setting the index for the tabBarController instance of the app delegate like yourAppDelegate.tabBarController
If you are using tabBarController as IBOutlet , there is no need to allocate it in your app delegate. Please remove these code from your appDelegate method (application: didFinishLaunchingWithOptions)..
tabBarController = [[UITabBarController alloc] init];
[tabBarController setDelegate:self];

Table and normal view inside of Tab Bar. Cannot see text on Bars

I am attempting to create an app where there is a tab bar on the bottom, and the first tab is supposed to be labeled "Bets" and the second is to be labeled "Settings". However, I attempted to change it in IB but it seems as though something is blocking the text from being seen, although you can see the bar and buttons at the bottom
DollarBetAppDelegate.h
#import <UIKit/UIKit.h>
#import "User.h"
#interface DollarBetAppDelegate : NSObject <UIApplicationDelegate,
UITabBarControllerDelegate> {
UIWindow *window;
UITabBarController *tabBarController;
UINavigationController *navController;
User *main;
}
#property (nonatomic,retain)User *main;
#property (nonatomic, retain) IBOutlet UIWindow *window;
#property (nonatomic, retain) IBOutlet UITabBarController *tabBarController;
#end
DollarBetAppDelegate.m
#import "DollarBetAppDelegate.h"
#import "BetsViewController.h"
#import "SettingsViewController.h"
#import "User.h"
#import "Bet.h"
#implementation DollarBetAppDelegate
#synthesize window;
#synthesize tabBarController;
#synthesize main;
#pragma mark -
#pragma mark Application lifecycle
- (BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
main = [[User alloc]init];
Bet *bet;
bet = [[Bet alloc]init];
NSLog(#"bet.betDesc = %# \n", bet.betOwner);
[main.betArray addObject:(Bet*)bet];
// Add the tab bar controller's view to the window and display.
BetsViewController *bvc = [[BetsViewController alloc] init];
SettingsViewController *svc = [[SettingsViewController alloc]init];
bvc.mainUser = main;
navController = [[UINavigationController alloc] initWithRootViewController:bvc];
[bvc release];
tabBarController.viewControllers = [NSArray arrayWithObjects:navController, svc,
nil];
[navController release];
[svc release];
[self.window addSubview:tabBarController.view];
[self.window makeKeyAndVisible];
return YES;
}
#pragma mark -
#pragma mark Memory management
- (void)applicationDidReceiveMemoryWarning:(UIApplication *)application {
/*
Free up as much memory as possible by purging cached data objects that can be recreated
(or reloaded from disk) later.
*/
}
- (void)dealloc {
[tabBarController release];
[window release];
[super dealloc];
}
#end
This is the end result when compiled
http://i55.tinypic.com/2zduf7c.png
If any other files are needed, let me know.
I appreciate any input.
From the UITabBarController class reference:
"If you do not provide a custom tab bar item for your view controller, the view controller creates a default item containing no image and the text from the view controller’s title property."
Your view controllers (BetsViewController and SettingsViewController) should set the title property in the initializer method.

iPhone navigationController is not displayed

I have a very strange behaviour of my navigation view. What I want is, that from my main view, the user can touch a button, which leads him to the view with the application settings.
Here is the code, responsible for the navigation:
AppDelegate.h
#interface AppDelegate : NSObject {
UIWindow *window;
ViewController *viewController; // My Main View Controller
UINavigationController *navigationController; }
#property (nonatomic, retain) IBOutlet UIWindow *window;
#property (nonatomic, retain) IBOutlet ViewController *viewController;
#property (nonatomic, retain) IBOutlet UINavigationController *navigationController;
AppDelegate.m
#synthesize viewController;
#synthesize window;
#synthesize navigationController;
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
[window addSubview:viewController.view];
[window addSubview:navigationController.view];
[window makeKeyAndVisible];
return YES;
}
viewController.h
#import
#import "optionsViewController.h" // the 'settings' view controller
#class AppDelegate;
#interface ViewController : UIViewController {
AppDelegate *appDelegate;
viewController.m
- (IBAction)showOptionsViewController:(UIBarButtonItem *)sender {
// optionsController.theSubjectID = self.theSubjectID;
// [self presentModalViewController:self.optionsController animated:YES];
optionsViewController *optionsController= [[optionsViewController alloc] initWithNibName:#"optionsViewController" bundle:nil];
optionsController.theSubjectID = self.theSubjectID;
[self.navigationController pushViewController:optionsController animated:YES];
[optionsController release];
}
My optionsController is a 'normal' UIViewController. As you see did I change the load of the optionsController from modal to navigation. Could it be, that I missed something here?
Thanks for any hints in advance.
Cheers, René
Have you connected it up in Interface Builder if not you need to alloc/init it before you add it as a subview?

Programmatically created ViewController and awakeFromNiB?

I am creating a viewController programmatically (hopefully the right way) My problem is that I previously created the controller in IB and have code I want to call in awakeFromNib. As I currently have things viewDidLoad works fine but awakeFromNib does not. Is there anyway to get awakeFromNib to call or an alternative method that I can use in its place?
#class MyViewController;
#interface TEST_ControllerAppDelegate : NSObject <UIApplicationDelegate> {
UIWindow *window;
MyViewController *viewController;
}
#property(nonatomic, retain) IBOutlet UIWindow *window;
#end
.
#implementation TEST_ControllerAppDelegate
#synthesize window;
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
viewController = [[MyViewController alloc] init];
[window addSubview:[viewController view]];
[window makeKeyAndVisible];
return YES;
}
- (void)dealloc {
[viewController release];
[window release];
[super dealloc];
}
#end
EDIT_001:
I have pretty much come to the conclusion that using viewDidLoad is going to be my best option, particularly as I want to initialise IBOutlet instance variables.
In order to be called, the awakeFromNib method must be parameter-less (no sender):
- (void)awakeFromNib {
// Do whatever is needed...
}
Take care of the casing, as no error or warning will be logged if you mistype the method.