I have a LoginViewController class that extends UIViewController that is only displaying for a fraction of a second. In my AppDelegate.m class I try to allocate a UINavigationController that will have LoginViewController as a child view controller. I see loginViewController's view for a split second before the view goes black (I see the view I designed in Interface Builder). I'm not really sure why this is occurring.
Aside from the view flashing quickly, I was running the app on a 2nd gen iPod touch and noticed I could swipe my thumb to the right and see apps from the home screen. One more swipe and I could see search, but icons at the bottom such as music, mail, safari, and videos were not visible. Pressing stop button killed the app and returned to a normal home screen. This makes me think I'm setting the root view controller incorrectly? I took the if respondsToSelector code from another question here on Stack Overflow. The if stopped my code from crashing which I think has something to do with devices older than iOS 4? When it ran without crashing is when I started receiving login view flashing just once and the home screen apps are just a thumb swipe away.
Any help is appreciated. If more of my code would help explain my question just let me know and I'll post more.
Edit: Forgot to post Xcode Version 4.4 and Deployment iOS targeted 4.0
AppDelegate.m:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease];
mainViewController = [[[MainViewController alloc] initWithNibName:#"MainViewController" bundle:nil] autorelease];
loginViewController = [[[LoginViewController alloc] initWithNibName:#"LoginViewController" bundle:nil] autorelease];
navigationController = [[UINavigationController alloc] init];
[navigationController pushViewController:loginViewController animated:NO];
if([window respondsToSelector:#selector(setRootViewController:)])
{
[window setRootViewController:navigationController];
}
else
{
[window addSubview:[navigationController view]];
}
initWithRootViewController:viewController] autorelease];
initWithNibName:#"ContainerViewController" bundle:nil] autorelease];
[window makeKeyAndVisible];
return YES;
}
Take out the autorelease in your window-creating line. You want the window to live as long as the application is running.
Related
my project runs without storyboards, so im loading my view inside AppDelegate:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
UIWindow *window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
self.window = window;
self.window.rootViewController = [[SYLoginController alloc] init];
[self.window makeKeyAndVisible];
return YES;
}
It used to work on iPhone 6 sim 9.3 but now, on all simulators it only shows a black screen. But on my iPhone 6 Device it works. Whereas on another iPhone 6 it also shows a black screen. Those two iPhones are literally the same 16gb iPhone 6 bought at nearly the same time.
In SYLoginControllers viewDiDLoad I'm logging the text of one of the buttons. Only on my device it prints the text, on all simulators and the other iPhone it prints (null), so i assume that the xib is not properly loaded.
SYLoginController is a UIViewController, and the related xib holds a UIView with its FilesOwner set to SYLoginController. I really can't see why it only works on this particular device. Also i tried [[SYTabBarController alloc] initWithNibName:#"SYLoginController" bundle:nil], this also does not work...
Did you tried to wrap it arround a Navigation Controller?
SYLoginController *syVC = [[SYLoginController alloc]initWithNibName:#"SYLoginController" bundle:nil];
UINavigationController *nav = [[UINavigationController alloc] syVC];
self.window.rootViewController = nav;
Also check again if Custom Class is set to SYLoginController in the XIB-File. And the View is connected to the Files Owner.
I have been playing around with this for a couple of days and I cannot figure this out.
-> Basically I want to implement a simple login view that has a button when clicked, goes to go to the navigation controller ( in my case is "viewController" with buttons that link to mini math games which are other views).
-> Login screen should be displayed first, than navigation controller's root view when a button is clicked on the login screen
-> I have tried to declare the navigation controller when I click the button of the login screen but that seems to not work
-> Is it safe to say that a navigation controller can only be initialized in the apple delegate?
Currently I have this in my apple delegate declaring and setting my navigational controller:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions: (NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// Override point for customization after application launch.
self.viewController = [[ViewController alloc] initWithNibName:#"ViewController" bundle:nil];
UINavigationController *navigationViewController = [[UINavigationController alloc] initWithRootViewController:self.viewController]; // self.viewController is the main screen
self.window.rootViewController = navigationViewController; // set root to navigationViewController
[self.window makeKeyAndVisible];
return YES;
}
Any ideas will be appreciated. Thank you for your time !
Your code in the app delegate looks ok. NavigationController does not need to be declared in the AppDelegate. In your case, it is definitely ok to declare it upon login button pressed.
Try this at the login event:
UIViewController *nextVC = [[UIViewController alloc] init];
UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:nextVC];
[self presentViewController:navController animated:YES completion:^{
}];
What I would do would be set the loginViewController as the rootViewController of the navigation. And after check if login was done successfully, you could implement [self performSegueWithIdentifier:#"identifier"] setting the game viewController as destination. (Using Storyboard would make your life much easier). Well, that's my opinion :)
I have been having some memory management issues and random crashes with my app. I have done a lot of work on it to try to clean up the code generally and have converted the project to ARC.
I now have a clear view on the problem - essentially the app does not release views so as a user moves through the app each view is reloaded and retained until finally the app crashes due to memory issues.
I have a UINavigationController. My app runs only in landscape left orientation. When i use
[window setRootViewController:viewController];
on load and then
[self.window addSubview:[finalViewController view]];
the new view is displayed in portrait - if i rotate it to landscape left with code when i load it in, then all kinds of other random issues come up.
If instead of addSubview i use
[self.viewController.view removeFromSuperview];
[self.window setRootViewController:finalViewController];
viewController = nil;
self.viewController = nil;
window.viewController = nil;
rotation is ok but views are not released and i have a memory issue with the app and it crashes eventually. Any thoughts would be awesome - appreciate i'm probably missing something fairly basic here. Thanks & happy holidays!
How are you loading new views in your app? If you are using a UINavigationController, your AppDelegate should start something like this:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
RootViewController* rootController = [[RootViewController alloc] init];
UINavigationController* navController = [[UINavigationController alloc] initWithRootViewController:rootController];
[self.window setRootViewController:navController];
[self.window makeKeyAndVisible];
return YES;
}
To load another view(say from a button press) you will do something like this from within the root view:
SecondViewController *secondView = [SecondViewController alloc] init];
[self.navigationController pushViewController:secondView animated:YES];
This will make the UINavigationController responsible for memory management of your views.
As for rotation, that is handled by giving each of your ViewControllers this method:
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
if(interfaceOrientation == UIInterfaceOrientationLandscapeLeft) return YES;
return NO;
}
Aslong as you are using the UINavigationController the way it is meant to be used, you should not have any non-releasing views. You should read into the UINavigationController: http://developer.apple.com/library/ios/#documentation/uikit/reference/UINavigationController_Class/Reference/Reference.html
Another possibility is that the childviews of your view controllers have strong references to their parent view/controller. This will stop a parent viewcontroller from deallocating due to it giving its child a retain count of 1 and the child giving the parent a retain count of 1 as well. Here is a SO post with information on strong & weak references: Objective-C declared #property attributes (nonatomic, copy, strong, weak)
I am developing a xib-based landscape-only app. The app launches in landscape correctly. However, the view in my main ViewController is presented in portrait. That is, it is rotated 90 degrees so that the image appears cropped and does not take up the entire screen. If I use my interface to present a modal view controller then return to the main ViewController, the issue corrects itself (the view is presented in landscape). This problem did not occur under Xcode 4.2. It occurred after upgrading to Xcode 4.3, and the only code changes that were made were automatically implemented by Xcode when I upgraded the project settings.
Based on advice in other posts, I verified my Info.plist settings for Supported Interface Orientations and Initial Interface Orientation. I overrode the shouldAutorotateToInterfaceOrientation method for each of my view controllers to return YES only for landscape orientations. Also, I turned off auto resizing for the view, as I never want the size/orientation of the view to change.
Based on the ideas in this link [1], I suspected the problem is that the view is not receiving the call to change orientation at launch, possibly due to the removal of the MainWindow.xib concept, which appears to be replaced by the following Xcode-inserted code in AppDelegate.m:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
self.viewController = [[ViewController alloc] initWithNibName:#"ViewController" bundle:nil];
self.window.rootViewController = self.viewController;
[self.window makeKeyAndVisible];
return YES;
}
I modified this method to generate a generic root view controller from which my ViewController class is presented, as shown in the code below:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
ViewController* myViewController = [[ViewController alloc] initWithNibName:#"ViewController" bundle:nil];
self.viewController = [[UIViewController alloc] init];
self.window.rootViewController = self.viewController;
[self.window makeKeyAndVisible];
[self.viewController presentModalViewController:myViewController animated:NO];
return YES;
}
Voila! This solved my problem. However, to me it feels like a change at a fundamental level, which I don't want to make at this point in my development. What I intended to be my root view controller is now a modal view. Does anyone have another solution to this issue?
Thanks in advance!
I had this same issue: an app which was meant to be in Landscape that assumed the ViewController was always in Portrait. I made tons of changes to every aspect of the project and info.plist, including giving the main UIWindow a root-view controller which was landscape. It still didn't work. I eventually undid all the changes and just added the two lines noted below to my app delegate:
- (void)applicationDidFinishLaunching:(UIApplication *)application
{
[_window addSubview:[_viewController view]];
glView = _viewController.glView;
// THIS FIXED ORIENTATION FOR ME IN IOS 6
_window.rootViewController = self.viewController;
[self.window makeKeyAndVisible];
// END
...my other setup code here...
}
Nothing else was necessary.
It appears that, for some reason, in iOS 6 the UIWindow root-view-controller setting is sometimes ignored in Interface Builder. I am sure my reasoning is wrong somewhere, but I thought this might well help prod someone in the direction of a fuller, more exhaustive answer.
In iOS 8, settings windows frame to the UIScreen is also necessary, as it won't get automatically updated.
self.window.frame = [UIScreen mainScreen].bounds;
I am new to iPad development (or iPhone for that matter :) ) and I am building an app with a Split View Controller.
The thing is the first screen should be a single screen. I want the user to write user/pass data to connect to a remote server, and there's not really anything to show in the master view.
I know I can return YES in the splitViewController:shouldHideViewController:inOrientation:, and that works fine for the first screen, but I'd like to get the two views when the user taps the login button and the credentials are validated.
I can put some condition in shouldHideViewController and that shows the two views in the second screen and only the detail in the first, but shouldHideViewController is only called if I rotate my iPad, not when I perform the segue.
Do you have any tips to do this? Should I change my UI approach to something else? Any suggestions are welcome.
starting from scratch is a good idea. You have more control over whats going on IMO.
At your starting point you want to add your LoginViewController.
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
self.loginController = [[LoginViewController alloc] initWithNibName:#"LoginViewController" bundle:nil];
self.window.rootViewController = self.viewController;
[self.window makeKeyAndVisible];
return YES;
}
Later when the authentication process has finished you want to continue with SplitView, right?
- (void)continueWithSplitView {
UINavigationController *leftNav = [[UINavigationController alloc] initWithRootViewController:self.masterViewController];
UINavigationController *rightNav = [[UINavigationController alloc] initWithRootViewController:self.detailViewController];
self.splitViewController.viewControllers = [NSArray arrayWithObjects:leftNav, rightNav, nil];
self.view.window.rootViewController = self.splitViewController;
}
Notice that in both methods your desired viewController is set as the rootViewController property of UIWindow. This will automatically add the view of your controller as the top level view in UIWindow.
Furthermore make sure that you are following the MVC pattern e.g. a model object for your credentials organisation.