I created a brand new project and created a new view controller with a button in the view.
I am adding the view in application:didFinishLaunchingWithOptions
- (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];
BOOL introDisplayed = [[NSUserDefaults standardUserDefaults] boolForKey:kIntroScreenSeenByUser];
if(introDisplayed)
{
}
else
{
IntroView *introView = [[IntroView alloc] initWithNibName:#"IntroView" bundle:nil];
[self.window addSubview:introView.view];
}
[self.window makeKeyAndVisible];
return YES;
}
.h file
#interface IntroView : UIViewController
#property (weak, nonatomic) IBOutlet UIButton *clickMe;
- (IBAction)clicked:(id)sender;
#end
.m file
#import "IntroView.h"
#interface IntroView ()
#end
#implementation IntroView
#synthesize clickMe;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
}
- (void)viewDidUnload
{
[self setClickMe:nil];
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
- (IBAction)clicked:(id)sender {
NSLog(#"clicked");
}
#end
Clicking on the button results in a EXC_BAD_ACCESS(code=2 error. Any ideas? I am using ARC.
Thanks
UPDATE
Created a public property on the application delegate called "introViewController" and changed the application:didFinishLaunchingWithOptions
#synthesize introViewController;
- (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];
BOOL introDisplayed = [[NSUserDefaults standardUserDefaults] boolForKey:kIntroScreenSeenByUser];
introViewController = [[IntroView alloc] initWithNibName:#"IntroView" bundle:nil];
if(introDisplayed)
{
}
else
{
[self.window addSubview:introViewController.view];
}
[self.window makeKeyAndVisible];
return YES;
}
This solved the error.
You're creating your IntroView controller, and adding it's view as a subview, but the controller itself is released. I don't think that adding the view controller's view (and then letting ARC discard the controller itself) is an acceptable way to create a view.
Perhaps you could make the IntroView view controller a property of the app delegate class and therefore it won't be released by ARC.
Personally, I don't monkey around with the app delegate's creation of the views and controllers, but rather I let my target settings and my NIBs dictate that. I presume you're doing this because you want to have some intro screen. If I wanted an screen, I'd have my main view controller go ahead and present whatever intro I want. That way when the intro is dismissed (or popped off, depending upon whether you pushed or presented modally), my main view controller is still at the top (and useful methods like popToRootViewController work perfectly).
Related
I have a button created using the .xib file. I want the app to autoload the first question (meaning the ViewController to autoload the "showQuestion" method when the app first started. I am a beginner. How do you do it? Please help! Thanks!
ViewController.m
- (instancetype)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil{
//call the init method implemented by the superclass
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
self.questions = #[#"What is your name?",
#"How old are you?",
#"Where are you from?"];
return self;
}
- (IBAction)showQuestion:(id)sender{
self.questionLabel.text = self.questions[currentIndex];
}
the AppDelegate.m file
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
ViewController *vc = [[ViewController alloc] init];
self.window.rootViewController = vc;
return YES;
}
In your -viewDidLoad method of the view controller, just manually call the -showQuestion method.
i.e. in your ViewController.m, add this:
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
[self showQuestion:nil];
}
Try like this:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
ViewController *vc = [[ViewController alloc] init];
self.window.rootViewController = vc;
// Autoload first question
[vc showQuestion:nil];
return YES;
}
ViewController.h
- (IBAction)showQuestion:(id)sender;
I have the following code in my main ViewController viewDidLoad function
window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
nav = [[NavWithAutoRotateViewController alloc] initWithRootViewController:self];
[window addSubview:[nav view]];
[window makeKeyAndVisible];
[[self navigationController] setNavigationBarHidden:YES];
My ipad app is currently set to only work in landscape mode and I'm using this new window to show a quicklook document and allowing the nav bar to provide a back button and save options for the document. Main problem is that the new UIWindow orientation doesn't match my main applications UIWindow.
I have a custom UINavigationController above called NavWithAutoRotateController and here is the code for that controller.
-(id)init
{
if(self)
{
// _supportedInterfaceOrientatoin = UIInterfaceOrientationMaskLandscape;
// _orientation = UIInterfaceOrientationLandscapeLeft;
}
return self;
}
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (BOOL)shouldAutorotate
{
return YES;
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation
{
return YES;
}
-(NSUInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskLandscapeLeft;
}
// Tell the system which initial orientation we want to have
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
{
return UIInterfaceOrientationMaskLandscape;
}
I think I have a solution. The problem seems to be in the assignment of UIViewController to the rootViewController in your extra UIWindow.
If you just assume that you can use the same view controller that your primary UIWindow is using, and then add things as subviews of the new UIWindow, there are orientation issues.
To solve this, I did the following:
UIWindow *newWindow = [[UIWindow alloc] initWithFrame: [UIApplication sharedApplication].keyWindow.frame];
newWindow.windowLevel = UIWindowLevelStatusBar+1;
// You can use a view controller instantiated from a xib or storyboard here if you want.
// Just don't use the view controller already set as a UIWindow's rootViewController.
UIViewController *newViewController = [[UIViewController alloc] init];
newWindow.rootViewController = newViewController;
[newWindow makeKeyAndVisible];
// Add something to the new UIWindow. Can use the new UIViewController's view:
[newViewController.view addSubview: myContentView];
// Or could add it as subview of UIWindow: - either works.
[newWindow addSubview: myContentView];
Doing it this way seems to have solved all the weird issues around rotation.
Hope this helps.
I was having the same problem. Orientation changes were being handled properly using the viewWillTransition method. But my problem was that in some edge case conditions, namely if my device was sitting at an odd angle, the custom UIWindow would initialize in portrait orientation, even though the rootViewController was in landscape. And viewWillTransition isn't called because the device isn't rotated on initial load. I found a really simple solution to my problem that worked in any situation I tested.
First initialize your custom UIWindow without a frame. Then set your frame. And voila.. its orientation is what you'd expect.
Swift
let customWindow = UIWindow()
customWindow.frame = CGRect(x: x, y: y, width: w, height: h)
customWindow.rootViewController = self //<your_viewController>
customWindow.windowLevel = .statusBar // or whatever level you need
customWindow.makeKeyAndVisible()
ObjC
UIWindow customWindow = [[UIWindow alloc] init];
customWindow.frame = CGRectMake(x, y, w, h);
customWindow.rootViewController = self;
customWindow.windowLevel = UIWindowLevelStatusBar;
[customWindow makeKeyAndVisible];
Register for status bar frame change notification which is only called (afaik) when orientation changes and then define your new window's orientation..
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(appWillChangeStatusBarFrameNotification:)
name:UIApplicationWillChangeStatusBarFrameNotification
object:nil];
I have an ItemsViewController of type
#interface ItemsViewController : UITableViewController
Now this I call from the appdelegate in the didFinishLaunchingWithOptions like so
ItemsViewController *itemsViewController = [[ItemsViewController alloc] initWithNibName:#"ItemsViewController" bundle:nil];
// Create an instance of a UINavigationController
// its stack contains only itemsViewController
UINavigationController *navController = [[UINavigationController alloc]
initWithRootViewController:itemsViewController];
// Place navigation controller's view in the window hierarchy
[[self window] setRootViewController:navController];
self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
return YES;
Now in ItemsViewController.m file I do hit this method :
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
but the problem here is that it never hit the viewdidload method?? What should I look for? I am confused!!
ok , well I found the problem, I've been doing so much editing of this project that I accidentally deleted the most important line in the beginning of the method didFinishLaunchingWithOptions. which is this :
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
Anyway, so I am going to kill myself now, feel free to recommend a method of death ( clorox cocktail, walk into traffic) , and if you wanna write some nice words about me to be published
in my eulogy too.
Thanks.
I have 2 view controllers. I want 1st viewcontroller to be Portrait mode only while 2nd viewController should support all orientations. Please help me.
In AppDelegate class, my code is :
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease];
self.viewController = [[[ViewController alloc] initWithNibName:#"ViewController" bundle:nil] autorelease];
UINavigationController * navController = [[UINavigationController alloc] initWithRootViewController:self.viewController];
self.window.rootViewController = self.viewController;
// [self.window addSubview:navController.view];
[self.window makeKeyAndVisible];
return YES;
}
- (NSUInteger)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window{
NSLog(#"supportedInterfaceOrientationsForWindow");
return UIInterfaceOrientationMaskAllButUpsideDown;
}
1st ViewController code is:
-(BOOL)shouldAutorotate
{
return NO;
}
-(NSUInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskPortrait;
}
// Tell the system which initial orientation we want to have
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation {
return UIInterfaceOrientationMaskPortrait;
}
2nd ViewController code is:
-(NSUInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskAllButUpsideDown;
}
-(BOOL)shouldAutorotate
{
return YES;
}
// Tell the system which initial orientation we want to have
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation {
return UIInterfaceOrientationMaskAllButUpsideDown;
}
What i inspect is 'shouldAutorotate' method is not called for 1st and 2nd ViewController.
Your quick help will highly be appreciable.
Thanks.
Kashif
Try to set supportedInterfaceOrientations for 2nd UIViewController like this:
- (BOOL) shouldAutorotate
{
return YES;
}
-(NSUInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskLandscapeRight; // add any other you want
}
Also, enable only portrait in same method in 1st UIViewController.
Maybe you need to enable those orientations also in project settings which 2nd UIViewController needs to support.
[edit #1: Added sample application]
Here you go sample application which solves your problem, hopefully.
AppDelegate.h
#import <UIKit/UIKit.h>
#class FirstViewController;
#interface AppDelegate : UIResponder <UIApplicationDelegate>
#property (strong, nonatomic) UIWindow *window;
#property (strong, nonatomic) FirstViewController *viewController;
#end
AppDelegate.m
#import "AppDelegate.h"
#import "FirstViewController.h"
#implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// Override point for customization after application launch.
self.viewController = [[FirstViewController alloc] initWithNibName:#"FirstViewController" bundle:nil];
self.window.rootViewController = self.viewController;
[self.window makeKeyAndVisible];
return YES;
}
- (void)applicationWillResignActive:(UIApplication *)application
{
// Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
// Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
}
- (void)applicationDidEnterBackground:(UIApplication *)application
{
// Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
// If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
}
- (void)applicationWillEnterForeground:(UIApplication *)application
{
// Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
}
- (void)applicationDidBecomeActive:(UIApplication *)application
{
// Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
}
- (void)applicationWillTerminate:(UIApplication *)application
{
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
}
#end
FirstViewController.h
#import <UIKit/UIKit.h>
#interface FirstViewController : UIViewController
- (IBAction)goToSecondViewController:(id)sender;
#end
FirstViewController.m
#import "FirstViewController.h"
#import "SecondViewController.h"
#interface FirstViewController ()
#end
#implementation FirstViewController
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self)
{
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
}
-(BOOL)shouldAutorotate
{
return NO;
}
-(NSUInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskAll;
}
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
{
return UIInterfaceOrientationMaskPortrait;
}
- (IBAction)goToSecondViewController:(id)sender
{
SecondViewController *svc = [[SecondViewController alloc] initWithNibName:#"SecondViewController" bundle:nil];
[self presentViewController:svc animated:NO completion:nil];
}
#end
SecondViewController.h
#import <UIKit/UIKit.h>
#interface SecondViewController : UIViewController
- (IBAction)goToFirstViewController:(id)sender;
#end
SecondViewController.m
#import "SecondViewController.h"
#interface SecondViewController ()
#end
#implementation SecondViewController
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self)
{
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
}
-(NSUInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskAll;
}
-(BOOL)shouldAutorotate
{
return YES;
}
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
{
return UIInterfaceOrientationLandscapeLeft;
}
- (IBAction)goToFirstViewController:(id)sender
{
[self dismissViewControllerAnimated:NO completion:nil];
}
#end
FirstViewController.xib
SecondViewController.xib
As per your description , first view controller pushed into navigation controller. Your method definition of shouldAutorotate and supportedInterfaceOrientations are absolutely correct. During orientation changes, your navigation Controller's shouldRotate only fired and won't fired your first view controller's(child of nav controller) shouldAutorotate. So you have to category navigationController in your view controller or in seperate file and import into it wherever needed. Code as below for UINavigation Controller category.
.h file have this code
#interface UINavigationController (autoRotate)
-(BOOL)shouldAutorotate;
- (NSUInteger)supportedInterfaceOrientations;
#end
.m file have this code
#import "UINavigationController+autoRotate.h"
#implementation UINavigationController (autoRotate)
-(BOOL)shouldAutorotate
{
return [[self.viewControllers lastObject] shouldAutorotate];
}
-(NSUInteger)supportedInterfaceOrientations
{
return [[self.viewControllers lastObject] supportedInterfaceOrientations];
}
If you write category in separate file, you have to import .h file in your first and second view controllers as #import "UINavigationController+autoRotate"
a simple solution:
implement : - (NSUInteger)supportedInterfaceOrientations
when asked from AppDelegate.m
- (NSUInteger)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window
for more detail already answered here:
iOS 6 landscape and portrait orientation
SOLUTION
Make sure in the plist that the storyboard name is listed as the main storyboard file name.
I have a Storyboard with a UINavigationViewController that's connected to a NavigationViewController class and it's set as the UIWindow rootViewController. When the app runs (in the Simulator (5.1)) I get a blank black screen with the blue-ish navigation bar on the top.
The first problem is that in the storyboard, I set the navigation bar to black. I also set the status bar to translucent black. Neither styles are being honored when the app runs.
And the second problem is that the navigation controller's view is empty even though in the storyboard it has a relationship to a UITableViewController.
How can I fix both of these issues. I just started using Xcode again and had been using 4.0 before so the storyboards are throwing me off...
UPDATE
Here's the code as requested. Obviously I can't post the storyboard (can I?).
AppDelegate:
#import "AppDelegate.h"
#implementation AppDelegate
#synthesize window = _window;
#synthesize navigationController;
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
navigationController = [[NavigationViewController alloc] init];
self.window.rootViewController = navigationController;
[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 {
}
#end
NavigationViewController:
#import "NavigationViewController.h"
#interface NavigationViewController ()
#end
#implementation NavigationViewController
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
}
return self;
}
- (void)viewDidLoad {
[super viewDidLoad];
}
- (void)viewDidUnload {
[super viewDidUnload];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
#end
The problem is that you are setting as the root controller a completely blank root controller, not the one from the story board. What you want to do is to delete that part of the code, and simply on the storyboard click the thing that says "is initial view controller"
When using storyboards you usually dont have to modify the appdelegate, because xcode sets which is the initial view that will appear and all of that based solely on how you set the storyboard. You can check this in the plist where it says which storyboard will be used as the main one.
If you want to load your navigation controller like that then you can do something like that you would have to get the viewcontroller from the storyboard itself and present it.
instantiateViewControllerWithIdentifier
but there is no need for that when using storyboards as it automatically loads whichever is set as the initial one (which can be seen as the viewcontroller with the arrow pointing at it)
Your app delegate method should look like this
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
return YES;
}