I have a custom view controller named CKCalendarViewControllerInternal.
CKCalendarViewControllerInternal
This class is the subclass of UIViewController.
CkCalendarViewController
I have a custom view controller named CKCalendarViewController. It's a subclass of UINavigationController as follow:
#interface CKCalendarViewController : UINavigationController <CKCalendarViewDelegate, UINavigationControllerDelegate>
This class is initialize with the CKCalendarViewControllerInternal as follow:
- (id)init
{
CKCalendarViewControllerInternal *calendarViewController = [CKCalendarViewControllerInternal new];
self = [super initWithRootViewController:calendarViewController];
}
Now, In AppDelegate my first view is as follow:
AppDelegate.m
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.viewController = [[[ViewController alloc] initWithNibName:#"ViewController" bundle:nil] autorelease];
UINavigationController *n1=[[UINavigationController alloc]init];
n1.viewControllers=[[NSArray alloc]initWithObjects:self.viewController, nil];
self.window.rootViewController=n1;
[self.window makeKeyAndVisible];
return YES;
}
CkDemoViewController
This class is the subclass of CkCalendarViewController as follow
#interface CKDemoViewController : CKCalendarViewController
ViewController.m
When i try to push the CKDemoViewController on button clicked.
Error & Question
It shows me error like
Exception: Pushing a navigation controller is not supported
Exception: [NSException]:Pushing a navigation controller is not supported
ex.name:'NSInvalidArgumentException'
ex.reason:'Pushing a navigation controller is not supported'
Reason for error
This is because the CKCalendarViewController is the subclass of UINavigationController.
If i try to open the modal view, it works perfectly.
But How can i initialize the CKCalendarViewController as shown above with the CKCalendarViewControllerInternal class??
Thank you,
Answer will greatly appreciate
If I understand correctly what you are doing, the simplest "hackish" way to make things work would be making CKCalendarViewController derive from CKCalendarViewControllerInternal. I am suggesting this because I see that you are trying to use your CKCalendarViewController as a normal view controller, so there should be no reason to have it be a navigation controller.
Another possibility would be for you to actually use your CKCalendarViewController as a navigation controller by doing this in your app delegate:
UINavigationController *n1 = [[CKCalendarViewController alloc]init];
n1.viewControllers = [[NSArray alloc]initWithObjects:self.viewController, nil];
self.window.rootViewController = n1;
but this depends on what you are trying to achieve.
More generally, if you are interested in "nesting" controllers within controllers, you should learn about controller containment. In controller containment, what you do to add a controller to another one is basically this:
[vc willMoveToParentViewController:self];
[self addChildViewController:vc];
[self.view addSubview:vc.view];
[vc didMoveToParentViewController:self];
Related
I'm not using a storyboard or anything. I'm just creating the cocoa classes and linking them up individually. I can get to load up the default View Controller which is SplashViewController but i can't get past there.
I have experience in php, android programming and python, but i'm totally clueless on how Obj-C and how the iOS framework works :(
SplashViewController.m
-(void)initializeInterface
{
//Initialize start button
[self.startButton addTarget:self action:#selector(startActivity) forControlEvents:UIControlEventTouchDown];
//Initialize fading backgrounds
[self animateImages];
}
-(void)startActivity
{
PhoneViewController *phoneView = [[PhoneViewController alloc] initWithNibName:#"PhoneViewController" bundle:nil];
[self.navigationController pushViewController:phoneView animated:YES];
}
SplashViewController.h
#import <UIKit/UIKit.h>
#import "PhoneViewController.m"
#class PhoneViewController;
#interface SplashViewController : UIViewController
#property (strong, nonatomic) PhoneViewController * phoneViewController;
#property UIImage *splashbg1;
#property UIImage *splashbg2;
#property (nonatomic, retain) IBOutlet UIImageView *splashbg;
#property (nonatomic, retain) IBOutlet UIButton *startButton;
-(void)initializeInterface;
-(void)animateImages;
-(void)startActivity;
#end
EDIT
classAppDelegate.m
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// Override point for customization after application launch.
self.window.backgroundColor = [UIColor whiteColor];
//Move from delegate view controller to root view controller
self.window.rootViewController=[SplashViewController new];
[self.window makeKeyAndVisible];
return YES;
}
Wrap your splash view controller in a navigation controller.
Otherwise, the navigationController property of your splash view controller is nil and pushViewController has no effect.
UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController: splashViewController];
To move from one UIViewController to other UIViewController, you can try the following things
If SecondViewController *secondViewController is the UIViewController you want to move in to, then your can do the following:
[self presentViewController: secondViewController animated:YES completion:nil];
This is when you UIViewController is not embedded inside a UINavigationController.
It is possible to create your view controllers entirely in code without using Storyboards or XIB files, but it's not recommended. It's like trying to write a complex user application in assembler. The state of the art has evolved since the days when that was necessary. There are better tools. Use them.
Creating everything yourself is both quite complex and not very well documented. You are setting yourself up for a very frustrating, error-prone process. I've been doing iOS development pretty much full time since 2009, and I would not attempt this.
That being said, if you are a masochist, you would create your view controller using initWithNibName:bundle:, passing in nil for both parameters, and then implement the loadView method. In loadView you're create your view hierarchy and install it.
If you are new to iOS/Objective-C, DO NOT DO THIS. It is like trying to write a kernel device driver in machine code as your first foray into UNIX.
Change you AppDelegate method as below -
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// Override point for customization after application launch.
self.window.backgroundColor = [UIColor whiteColor];
UINavigationController *navcon = [[UINavigationController alloc]initWithRootViewController:[SplashViewController new]];
//Move from delegate view controller to root view controller
self.window.rootViewController=navcon;
[self.window makeKeyAndVisible];
return YES;
}
Problem in your code, you have not taken any navigationController, that enables you push or pop UIViewController. Doing above you can use your method -(void)startActivity to Start a new ViewController.
I am writing tests to verify that a new view controller of a certain type is pushed on a navigation controller's stack when a certain action is made. However, I'm finding that calling pushViewController does not result in my UIViewControllers list of view controllers being updated nor the top one being the newly pushed controller.
Here's an abbreviated version of my test class:
#import "RRViewController.h"
#import "RestroomDetailsViewController.h"
#implementation RRViewControllerTests
{
RRViewController *viewController;
...
UINavigationController *navigationController;
}
- (void)setUp
{
[super setUp];
viewController = [[RRViewController alloc] init];
...
navigationController = [[UINavigationController alloc] initWithRootViewController:viewController];
}
...
- (void)testSelectingRestroomPushesNewViewController
{
[viewController userDidSelectRestroom];
UIViewController *currentTopViewController = navigationController.topViewController;
XCTAssertFalse([currentTopViewController isEqual:viewController], #"New view controller should be pushed onto Navigation Controller stack.");
XCTAssertTrue([currentTopViewController isKindOfClass:[RestroomDetailsViewController class]], #"New view Controller should be an RestroomDetailsViewController.");
}
And here is the RRViewController class with that userDidSelectRestroomn method called on viewController:
#import "RestroomDetailsViewController"
...
- (void)userDidSelectRestroom
{
RestroomDetailsViewController *nextViewController = [[RestroomDetailsViewController alloc] init];
[[self navigationController] pushViewController:nextViewController animated:YES];
}
The issue is that both of my tests are failing. Taking a look at navigationController.viewControllers in the RRViewControllerTests test class after userDidSelectRestroom is called shows:
<__NSArrayI 0x7ffaf9d37020>(
<RRViewController: 0x7ffaf9eba420>
)
i.e. just the original root RRViewController.
Any thoughts as to why the new RestroomDetailsViewController is not pushed onto navigationController's stack?
I want to use storyboard in my old project (which was implemented using xibs) for adding a new features.
I have created storyboard file and added a view controller to it and in Identity inspector I have specified the class name for the view controller.
#implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:[[FirstViewController alloc]initWithNibName:#"FirstViewController" bundle:[NSBundle mainBundle]]];
self.window.rootViewController = navController;
[self.window makeKeyAndVisible];
return YES
}
#end
In the firstviewcontroller when i click on a button it will call the gotoSomeviewController method where it pushes to the eventslistViewController loading from EventsScreen storyboard
#implementation FirstViewController
-(void)gotoSomeviewController
{
EventsListViewController *vc = [[UIStoryboard storyboardWithName:#"EventsScreen" bundle:nil] instantiateInitialViewController];
[controller pushViewController:vc animated:YES];
}
#end
when I'm running application the EventsListViewController is showing a empty screen without the views I have added in storyboard.
Based on the information supplied there should be no reason why you mix NIBs and Storyboard.
I would setup just a storyboard. Remove the app Delegate code and setup the project to load the storyboard for the specific device.
Setup your storyboard to have the initial view controller as a UINavigationController that has the FirstViewController as the root of that.
Then you can simply drag to the SecondViewController from the button and select push as the move option. Then remove your method for gotoviewcontroller. There is no reason why you would have this setup like this...
I am relatively new to iOS, hence I apologize for any inconsistency in my question. I need help with the following issue with an app I'm trying to build. My issue is this: The app i am working has a navigation based functionality with a tableview(daily filled by user) and a detailed tableview listing the inputs of the user, but this is just one functionality of the app.
I want to have a main tab based view where one of the tabs(each tab representing a functionality) points to this module.
I wanted to ask for steps and changes i need to make to for example app delegate or rootviewcontroller(I can post the code if it helps better) to make is so that the app starts with a mutli-tabbed bar view where one tab refers to view linked to the rootviewontroller of the navigation-based app.
For summary: Need a main tab bar view where one tab points to the rootviewcontroller highlighted in the screenshot(link below)
If helpful here is a relevant function code i have in app delegate :
- (void)applicationDidFinishLaunching:(UIApplication *)application
{
UINavigationController *navigationController = (UINavigationController *)self.window.rootViewController;
RootViewController *rootViewController = (RootViewController *)[[navigationController viewControllers] objectAtIndex:0];
rootViewController.managedObjectContext = self.managedObjectContext;
//Next TWO LINES FOR COLOR BACKGROUND
[[UINavigationBar appearance] setBackgroundImage:[[UIImage alloc] init] forBarMetrics:UIBarMetricsDefault];
[[UINavigationBar appearance] setBackgroundColor:[UIColor redColor]];
}
PS:Here is the screenshot for the storyboard: where i would like to have one tab refer to the view(highlighted in the screenshot) which is linked class rootviewcontroller.m/h
The screenshot: http://i.stack.imgur.com/G9AXI.png
edit: The actual question can be seen as: How and what do i need to do to have a tabbarviewcontroller which i would add with storyboard become my rootviewcontroller instead of the navigationcontroller(highlighted in black in the screenshot: http://i.stack.imgur.com/G9AXI.png).
My current rootviewcontroller.m manages anything related to the tableview of the current navigationviewcontroller, do i need to change that also?.
I apologize for excessiv details, I am really new to iOS dev.
From this one http://i.stack.imgur.com/suLBm.png I tried to embedd in tab barviewcontrol only with storyboard to this one http://i.stack.imgur.com/TZxLo.png I tried to embedd in a tab controller just by story but i get an error :'NSInvalidArgumentException', reason: '-[UIViewController setManagedObjectContext:]: unrecognized selector sent to instance 0x8184e30'
classes related to this are(especially rootviewcontroller.m which is a navigationcontroller for now:
AppDelegate.{h,m}
Configures the Core Data stack and the first view controllers.
- (void)applicationDidFinishLaunching:(UIApplication *)application
{
UINavigationController *navigationController = (UINavigationController *)self.window.rootViewController;
RootViewController *rootViewController = (RootViewController *)[[navigationController viewControllers] objectAtIndex:0];
rootViewController.managedObjectContext = self.managedObjectContext;
}
RootViewController.{h,m}
Manages a table view for listing all values entered. Provides controls for adding and removing these values.
- (void)viewDidLoad
{
[super viewDidLoad];
self.navigationItem.leftBarButtonItem = self.editButtonItem;
}
DetailViewController.{h,m}
Manages a detail display for display details of each entered value.
My initial guess is that i need to change the rootviewcontroller appdidfinishlaunching.
Any suggestions ?
In fact now you have:
- (void)applicationDidFinishLaunching:(UIApplication *)application
{
UITabBarController *tabController = (UITabBarController *)self.window.rootViewController;
RootViewController *rootViewController = (RootViewController *)[[[[tabController viewControllers] objectAtIndex:0] viewControllers] objectAtIndex:0];
rootViewController.managedObjectContext = self.managedObjectContext;
}
So you actually need a UITabBarViewController in the Storyboard and you can point to the UINavigationController if you want the ability to push other controllers.
You don't need other UINavigationControllers as I saw in your screenshot, as long as the rootviewcontroller is an UINavigationController.
You can add the UINavigationController as first of the tabs and then you can go and fill the other tabs with the viewcontrollers that you need displayed.
SO basically you need to create UITabBarController as rootviewcontroller.
Let me know if I understood your question correctly.
Here is an example of UITabBarController :
- (void)applicationDidFinishLaunching:(UIApplication *)application
{
//Here you set your controller
UIViewController* centerController = [[UIViewController alloc]init];
UINavigationController *navCenter = [[[UINavigationController alloc] initWithRootViewController:centerController] autorelease];
UITabBarController *tabBarController = [[[UITabBarController alloc] init] autorelease];
tabBarController.viewControllers = [NSArray arrayWithObjects:navCenter,nil];
self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease];
self.window.rootViewController = tabBarController;
return YES;
}
Let me know if it worked.
You should have something like this :
This question might have been answered, if yes, please share the link.
I have created a Single View Application, It works fine, but now I have added a new view and on a button click, wants the new view to appear.
This is the code for click action,
SettingsViewController *settingsViewController = [[SettingsViewController alloc] initWithNibName:#"SettingsViewController" bundle:[NSBundle mainBundle]];
[self.navigationController pushViewController:settingsViewController animated:YES];
The Default ViewController now looks like this in .h file
#interface ViewController : UIViewController<UIImagePickerControllerDelegate, UINavigationControllerDelegate>
The SettingsViewController.m has a default
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil{}
Can I add another view to "Single View Application" like this or should I chose another template for my project ?
Thanks.
You need to create a UINavigationController in your AppDelegate. Then make your ViewController the rootViewController of the UINavigationController. Then you will be able to push and pop views.
Here is the code to create the rootViewController where mainNavigationController is the UINavigationController in your AppDelegate:
ViewController *vc = [[ViewController alloc] init];
mainNavigationController = [[UINavigationController alloc] initWithRootViewController:vc];
Once you have the ViewController set up as the rootViewController it will conform to the UINavigationController push and pop methods to create a stack of UIViewControllers.
That is fine. The single view application template is just a barebones template. You can add any type of navigation you like to it.
In iOS 5, switching between views works a bit different i think,
I have created a few apps with the above mentioned code for switching views.
But now, I have to write it like this to work:
SettingsViewController *settingsViewController = [[SettingsViewController alloc] initWithNibName:#"SettingsViewController" bundle:[NSBundle mainBundle]];
[self presentModalViewController:settingsViewController animated:YES];