UIView Login screen to tabbar logic - objective-c

Folks,
I'm having trouble with some navigation logic. Currently I have a simple two tabbed tabbar application. But I want to show a loginscreen in front. So that would be an UIView.
Currently the code is as follows:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
UIViewController *viewController1 = [[roosterViewController alloc] initWithNibName:#"roosterViewController" bundle:nil];
UIViewController *viewController2 = [[SecondViewController alloc] initWithNibName:#"SecondViewController" bundle:nil];
self.tabBarController = [[UITabBarController alloc] init];
self.tabBarController.viewControllers = #[viewController1, viewController2];
self.window.rootViewController = self.tabBarController;
[self.window makeKeyAndVisible];
return YES;
}
So this pushes a simple tabcontroller. Well, now I want to have a login screen. So that would be a simple UIView which pushes the tabbar controller. But I can't seem to see the logic on how to do this.
I've been trying to present a modal view controller, but the thing is: the tabbar will be loaded on the background. Since I need the username/password information to work on the tabbarview, this won't work.
My Logic would be:
delegate > load loginViewController > load tabbar controller
But, then I need to be able to "logout". So I need to destroy the tabbar controller and present the login screen.
Any thoughts on this?

You could do something like this:
You could create a protocol which your AppDelegate conforms to.
#protocol Authenticator <NSObject>
#required
- (void)authenticateWithUsername:(NSString *)username andPassword:(NSString *)password;
- (bool)authenticated;
#optional
- (void)authenticationSuccess;
- (void)authenticationFailure;
...
#interface AppDelegate : UIResponder <UIApplication, Authenticator>
#property (readonly, nonatomic, assign) bool loggedIn;
...
#implementation AppDelegate
#synthesize loggedIn = _loggedIn;
- (void)authenticateWithUsername:(NSString *)username andPassword:(NSString *)password
{
//if success
_loggedIn = YES;
//check if app responds to the optional authenticateSuccess method
//call it if it does
//else fail
//do stuff
}
- (bool)authenticated
{
if (_loggedIn != NULL) {
return _loggedIn;
}
//do other stuff
}
...
I am a bit fuzzy on proper objective-c conventions and syntax so forgive me if I have a few errors, but anyways that is some logic and pseudo-code to work off of. Tweak that to your needs.
I hope this helps.
EDIT:
I guess my answer was a bit unfinished. It seemed to to me the answer to your question was strongly connected to some kind of authentication structure. If your app is so closely connected to authentication, then why not control its flow through the authentication structure. I guess that was my point, and since all this would be conveniently and readily available in your apps delegate, you could call these methods anywhere you wanted, therefore letting your authentication logic decide which view controller to show for example.

As mentioned have the login as the rootView and if the login is successful enable the other tabbarButtons else don't enable them like this..initially set the bool to false on view load then if successful enable a tabbar button else don't.
login = TRUE;
UITabBarItem *reportit = [[[[self tabBarController]tabBar]items] objectAtIndex:2];
[reportit setEnabled:TRUE];
else {
UITabBarItem *reportit = [[[[self tabBarController]tabBar]items] objectAtIndex:2];
[reportit setEnabled:FALSE];
}

I recommend you set the login screen as root. When the login is successful, you simply change the root of the window to the tabbar controller, with a nice animation.

I would recommend that you set up the tab bar just like you have it right now, but immediately following the makeKeyAndVisible you instantiate and present the login view controller, without animation.
This way once the app has launched the user does not see the tabBarController, but only the modally presented login screen. Once login is done you simply dismiss the login view controller and beneath it appears .... drumroll the tabbarcontroller!

Expanding on Levi's answer, this is how you switch the root view controller continuously (with an animation). Just add this extension:
extension UIViewController
{
func transitionToRootViewController(viewController:UIViewController)
{
UIView.transitionWithView(self.view.window,
duration: 0.3,
options: UIViewAnimationOptions.TransitionCrossDissolve,
animations: {
window.rootViewController = viewController
},
completion: nil
)
}
}
...to the UIViewController class (that will make the method transitionToRootViewController () available to all your view controllers), and call it on the exiting view controller, passing the entering view controller (that you perhaps instantiated form a separate storybord, who knows...) as a parameter.
(The basic idea was taken from here. I simplified the code a bit)
Beware though: I tried this code to insert a tab bar controller, whose selected index (tab) contained a navigation controller. During the transition animation, the navigation controller's navigation bar "underlaps" the status bar (carrier, clock, battery level), and only after the transition animation completes, it "jumps" into its place immediately, creating a horribly distracting (and unpolished) effect.
I fixed it by adding the following code to the child view controller embedded in the navigation controller:
override func viewWillAppear(animated: Bool)
{
super.viewWillAppear(animated)
self.navigationController?.navigationBar.layer.removeAllAnimations()
// ^ THIS
}
(This fix was taken from this forum.)
I haven't checked, but the same issue might occur whenever you transition into a navigation controller (or any plain-vanilla UIViewController that happens to have a navigation bar attached), whether it is embedded in a tab bar controller or not.

Related

how to display various view controllers (each having its respective navigation controller) using storyboard ID

I'm working on my first app. Here's what I want to accomplish:
There will be a menu with several different options. For simplicity, assume this is comprised of UIButtons with IBAction outlets and the functionality exists to pull up the menu at any time.
Each menu button, when pressed, should display a different navigation controller's content. If the user brings up the menu and makes a different selection, the navigation controller in which he is currently operating should not be affected; the newly selected navigation chain is displayed on top of the old, and through the menu, the user can go back to the view where he left off on the previous navigation chain at any time.
visual illustration (click for higher resolution):
Please note that there are 3 different navigation controllers/chains. The root view controller (which is also the menu in this simplified version) is not part of any of them. It will not suffice to instantiate one of the navigation chains anew when it has been previously instantiated, and here's why: if the user was on screen 3 of option 2 and then selects option 1 from the menu and then selects option 2 (again) from the menu, he should be looking at screen 3 of option 2--right where he left off; the view controller he was viewing when he previously left the navigation chain should be brought back to the top.
I can make a button instantiate and present a view controller from the storyboard if there is NOT a navigation controller:
- (IBAction)buttonPressed:(id)sender {
UIViewController *controller = [self.storyboard instantiateViewControllerWithIdentifier:#"View 2"];
[self presentViewController:controller animated:YES completion:nil];
}
However, I can't figure out how to make those two methods work with a navigation controller involved. Moreover, I'm not sure those two methods are the right choice, because I won't always want to instantiate a new view controller: when a menu button is pressed, a check should be performed to see if the view (navigation?) controller with the corresponding identifier has already been instantiated. If so, it should simply be made the top view controller.
In summary, here are my questions:
1) How should I instantiate and display a view controller that is embedded in a navigation controller, preferably using a storyboard ID? Do you use the storyboard ID of the navigation controller or of the view controller?
2) How should I check whether an instance already exists? Again, should I check for an extant navigation controller or for a view controller, and what's the best method to do so?
3) If the selected navigation chain has already been instantiated and is in the stack of view controllers somewhere, what is the best method for bringing it to the top?
Thank you!!
side note -- it would be nice to know how to paste code snippets with indentation and color formatting preserved :)
As Rob has suggested, a tab bar controller would make a good organising principle for your design.
Add a UITabBarController to your storyboard, give it a storyboard iD. Assign each of your three sets of viewControllers ( with their respective navController) to a tab item in the tabBarController.
UITabBarController
|--> UINavigationController --> VC1 ---> VC2 -->
|--> UINavigationController --> VC1 ---> VC2 -->
|--> UINavigationController --> VC1 ---> VC2 -->
In you app delegate make a strong property to hold your tab bar controller's pointer. As the tab bar controller keeps pointers to all of it's tab items, this will take care of state for each of your sets of viewControllers. You won't have to keep separate pointers for any of them, and you can get references to them via the tabBarController's viewControllers property.
#property (strong, nonatomic) UITabBarController* tabVC;
Initialise it on startup
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
UIStoryboard storyBoard =
[UIStoryboard storyboardWithName:#"MainStoryboard_iPhone" bundle:nil];
self.tabVC = [storyBoard instantiateViewControllerWithIdentifier:#"tabVC"];
//hide the tab bar
for (UINavigationController* navController in self.tabVC.viewControllers)
[navController.viewControllers[0] setHidesBottomBarWhenPushed:YES];
return YES;
}
An alternative way to hide the tab bar is to check the "Hides bottom bar on push" box in the Attributes Inspector for each of the (initial) viewControllers. You don't have to do this for subsequent viewControllers, just the first one that will be seen in that tab item.
Then when you need to navigate to one of your navController groups…
- (IBAction)openTab:(UIButton*)sender {
AppDelegate* appDelegate =
(AppDelegate*)[[UIApplication sharedApplication] delegate];
if ([sender.titleLabel.text isEqualToString: #"Option 1"]) {
appDelegate.tabVC.selectedIndex = 0;
}else if ([sender.titleLabel.text isEqualToString: #"Option 2"]){
appDelegate.tabVC.selectedIndex = 1;
}else if ([sender.titleLabel.text isEqualToString: #"Option 3"]){
appDelegate.tabVC.selectedIndex = 2;
}
[self presentViewController:appDelegate.tabVC
animated:YES completion:nil];
}
(this example uses presentViewController, your app design may navigate this in other ways…)
update
If you want to do this without a tab bar controller, you can instantiate an array holding pointers to each of your nav controllers instead:
UINavigationController* ncA =
[storyboard instantiateViewControllerWithIdentifier:#"NCA"];
UINavigationController* ncB =
[storyboard instantiateViewControllerWithIdentifier:#"NCB"];
UINavigationController* ncC =
[storyboard instantiateViewControllerWithIdentifier:#"NCC"];
self.ncArray = #[ncA,ncB,ncC];
Which has the benefit of not having a tab bar to hide…
Then your selection looks like…
- (IBAction)openNav:(UIButton*)sender {
AppDelegate* appDelegate =
(AppDelegate*)[[UIApplication sharedApplication] delegate];
int idx = 0;
if ([sender.titleLabel.text isEqualToString: #"option 1"]) {
idx = 0;
}else if ([sender.titleLabel.text isEqualToString: #"option 2"]){
idx = 1;
}else if ([sender.titleLabel.text isEqualToString: #"option 3"]){
idx = 2;
}
[self presentViewController:appDelegate.ncArray[idx]
animated:YES completion:nil];
}
1 / You can instantiate a viewController in your viewDidLoad method of your main viewController, so it will be instantiate 1 time only.
Now if you want display your controller, you would better push it :
- (IBAction)buttonPressed:(id)sender {
// Declare your controller in your .h file and do :
controller = [self.storyboard instantiateViewControllerWithIdentifier:#"View 2"];
// Note you can move this line in the viewDidLoad method to be called only 1 time
// Then do not use :
// [self presentViewController:controller animated:YES completion:nil];
// Better to use :
[self.navigationController pushViewController:controller animated:YES];
}
2 / I'm not sure, but if you want to check if an instance already exist just check :
if (controller) {
// Some stuff here
} // I think this checks if controller is initiated.
3 / I know it's not a good advice but I would tell you to not worry about checking if your controller already exist, because I think it's easier to access your viewController by using the 2 lines again :
controller = [self.storyboard instantiateViewControllerWithIdentifier:#"View 2"];
[self.navigationController pushViewController:controller animated:YES];
4 / I'm not sure if colors can be used here because of a specific style sheets.
I'm not sure to really have the good answer to your question but I hope this will help you.

UIView inside a UIViewController or better way to do it?

I have a problem on how to properly do a certain kind of action.
The image below shows a UIViewController, but the second part of the view is a custom UIView (the one with the profile pic, name and Show View button).
The subclassed UIView is allocated using this code:
profileView = [[GPProfileView alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, 70)];
profileView.myTripGradientColor = YES;
[self.view addSubview:profileView];
The problem is of course, that the button on the UIView can't show any view, since it's only the UIViewController that can push another ViewController to the window(correct?).
The UIView is used in several places in the app and needs to be added easily and have the same behavior across the application.
This worked great until I added the button, and I'm starting to think I've made this wrong, and there has to be a better way to do it (maybe change the UIView to something else?).
I was thinking I should be able to call:
self.superview
And then somehow get the ViewController so I can push another ViewController into the view hierarchy, but nope.
Any suggestions and a tips on how to do this correctly?
UPDATE:
I have no idea on how to push another UIViewController from the button.
What should I do in this method when pressing the button in the UIView:
- (void) showViewButtonTouched:(UIButton*)sender {
GPProfileSocialFriendsViewController *friendsSettings = [[GPProfileSocialFriendsViewController alloc] init];
}
How do I push GPProfileSocialFriendsViewController?
Your - (void) showViewButtonTouched:(UIButton*)sender method should be in your controller and would probably be better named - (void) showView:(UIButton*)sender or - (void) showProfile:(UIButton*)sender so it clearly denotes what it does (not how you got there).
It's not the view's responsibility to manage transitions from a state to another. If you move your method to your controller, your problem is no more (you can easily access self.navigationController or push directly if you don't have an navigation controller like this:
[self presentViewController:vcThatNeedsToBePushed animated:YES completion:nil];
I think you can create weak reference in GPProfileView on UIViewController. Like this:
#property (weak, nonatomic) UIViewController *rootController;
when you create GPProfileView, assign rootController-property:
profileView = [[GPProfileView alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, 70)];
profileView.myTripGradientColor = YES;
profileView.rootController = self; // if view created in view controller
[self.view addSubview:profileView];
and in implementation of button selector:
self.rootController push... // or pop
May be this not correct, but you can try
You could let the view controller push the next view controller when the button is pushed. The view controller can add a target/action on the button, so that the action method in the view controller is called on the touch up inside event.

Window ordering and XIB

I am setting my first steps in OSX development and I've run into some problems. I have quite some experience with iOS development but the window system for OSX programs is something else.
I am making a client for a social network like twitter and need 2 seperate window controller for first starting the app, one if you are logged in to show your timeline and one for logging in, if you are not yet logged in. In the info.plist you need to give it a main.xib. For this I made an empty xib which I hide, the second the app starts. This is not really a good solutions IMO, what is a better solution for this? I want to keep the windows seperate from the appdelegate because that way I can keep my code seperated.
This gives me a problem, when I open my 'second' window to login it shows up but isn't active. I have tried all the things like, orderFront:, activateIgnoringOtherApps:, makeKeyAndOrderFront: & more. But this all doesn't work..
So: First off, is there a better way to handle the main.xib that is needed in the info.plist and if not, is there a way around the focus problem?
I'm working om osx 10.7
For more than one-offs, you really ought to separate your app delegate from your window controllers. Go ahead and create a new Cocoa application from the template. In MainMenu.xib, delete the window. In AppDelegate.h delete the IBOutlet to the NSWindow. Create a couple new subclasses of NSWindowController complete with XIBs--perhaps LoginWindowController and TimelineWindowController.
For "final" NSWindowController subclasses (i.e. those which won't be subclassed), the best practice for designated initializers is
//for our example class LoginWindowController
- (id)init
{
self = [super initWithWindowNibName:#"LoginWindowController"];
if (self) {
//....
}
return self;
}
Now in your app delegate, you should have #properties for the two different window controller instances:
//Within AppDelegate.m
#import "AppDelegate.h"
#import "LoginWindowController.h"
#import "TimelineWindowController.h"
#interface AppDelegate ()
#property (nonatomic) LoginWindowController *loginWindowController;
#property (nonatomic) TimelineWindowController *timelineWindowController;
//For the sake of this demo, add a property for the loggedIn state:
#property (nonatomic) BOOL loggedIn;
#end
You ought to have some sort of method in your app delegate that presents the correct window controller. Let's call it -updateWindowVisibility:
- (void)updateWindowVisibility
{
BOOL isLoggedIn = self.loggedIn;
BOOL loginWindowVisible = self.loginWindowController.window.isVisible;
BOOL showLoginWindow = !isLoggedIn;
BOOL timelineWindowVisible = self.timelineWindowController.window.isVisible;
BOOL showTimelineWindow = isLoggedIn;
if (!loginWindowVisible && showLoginWindow) {
if (!self.loginWindowController) self.loginWindowController = [[LoginWindowController alloc] init];
[self.loginWindowController showWindow:nil];
} else if (loginWindowVisible && !showLoginWindow) {
[self.loginWindowController close];
self.loginWindowController = nil;
}
if (!timelineWindowVisible && showTimelineWindow) {
if (!self.timelineWindowController) self.timelineWindowController = [[TimelineWindowController alloc] init];
[self.timelineWindowController showWindow:nil];
} else if (timelineWindowVisible && !showTimelineWindow) {
[self.timelineWindowController close];
self.timelineWindowController = nil;
}
}
This method as implemented above does a tiny bit more work than is necessary given the present setup, but should be easier to modify when you need to show/hide other windows. All that's left to do at this point is to call -updateWindowVisibility from -applicationDidFinishLaunching:.
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
self.isLoggedIn = NO;
[self updateWindowVisibility];
}
I've posted an example app to github which demonstrates this approach.
In terms of structure (your first question), I would recommend this:
Create a XIB with one blank window and a big NSView (called, say, megaView) covering it. Create an IBOutlet in AppDelegate for your big NSView. Set the app to use this XIB on load.
Create two separate NSView XIBs: one for the state of being logged in, one for the state of being logged out. Put your layout in these.
Create two NSViewController subclasses: one controlling the logic of each NSView you just created. Let's call them LoggedOutViewController and LoggedInViewController.
Jump back to the two NSViews you created. Set the File Owner of your logged in NSView to LoggedInViewController and the File Owner of your logged out NSView to LoggedOutViewController. Hook up each File Owner's view (right-click on File Owner to find it) to the respective NSView.
In your app delegate, determine the user's authentication status in whatever way you need.
If logged in, do this:
NSViewController *loggedInController = [[NSViewController alloc] initWithNibName:#"NibNameGoesHere" bundle:nil];
[[self megaView] addSubview:[loggedInController view]];
Otherwise do the above process with your loggedOutController:
NSViewController *loggedOutController = [[NSViewController alloc] initWithNibName:#"OtherNibNameGoesHere" bundle:nil];
[[self megaView] addSubview:[loggedOutController view]];
That should get you what you want and will likely clear up your second question in the process. The difference between my answer and Nate's is that mine uses the same window. Instantiating view controllers conditionally and loading their views into superviews is probably the most important aspect of Cocoa I learned.

"Application tried to present modally an active controller"?

I just came across a crash showing a NSInvalidArgumentException with this message on an app which wasn't doing this before.
Application tried to present modally an active controller
UITabBarController: 0x83d7f00.
I have a UITabBarController which I create in the AppDelegate and give it the array of UIViewControllers.
One of them I want to present modally when tapped on it. I did that by implementing the delegate method
- (BOOL)tabBarController:(UITabBarController *)tabBarController shouldSelectViewController:(UIViewController *)viewController
If that view controller is of the class of the one I want to present modally, I return NO and do
[tabBarController presentModalViewController:viewController animated:YES];
And now I'm getting that error, which seems to mean that you can't present modally a view controller that is active somewhere else (in the tabbar...)
I should say I'm on XCode 4.2 Developer Preview 7, so this is iOS 5 (I know about the NDA, but I think I'm not giving any forbidden details). I currently don't have an XCode installation to test if this crashes compiling against the iOS4 SDK, but I'm almost entirely sure it doesn't.
I only wanted to ask if anyone has experienced this issue or has any suggestion
Assume you have three view controllers instantiated like so:
UIViewController* vc1 = [[UIViewController alloc] init];
UIViewController* vc2 = [[UIViewController alloc] init];
UIViewController* vc3 = [[UIViewController alloc] init];
You have added them to a tab bar like this:
UITabBarController* tabBarController = [[UITabBarController alloc] init];
[tabBarController setViewControllers:[NSArray arrayWithObjects:vc1, vc2, vc3, nil]];
Now you are trying to do something like this:
[tabBarController presentModalViewController:vc3];
This will give you an error because that Tab Bar Controller has a death grip on the view controller that you gave it. You can either not add it to the array of view controllers on the tab bar, or you can not present it modally.
Apple expects you to treat their UI elements in a certain way. This is probably buried in the Human Interface Guidelines somewhere as a "don't do this because we aren't expecting you to ever want to do this".
I have the same problem. I try to present view controller just after dismissing.
[self dismissModalViewControllerAnimated:YES];
When I try to do it without animation it works perfectly so the problem is that controller is still alive. I think that the best solution is to use dismissViewControllerAnimated:completion: for iOS5
In my case i was trying to present the viewController (i have the reference of the viewController in the TabBarViewController) from different view controllers and it was crashing with the above message.
In that case to avoid presenting you can use
viewController.isBeingPresented
!viewController.isBeingPresented {
// Present your ViewController only if its not present to the user currently.
}
Might help someone.
The same problem error happened to me when I tried to present a child view controller instead of its UINavigationViewController parent
I had same problem.I solve it. You can try This code:
[tabBarController setSelectedIndex:1];
[self dismissModalViewControllerAnimated:YES];
For React Native Developer - Problem might not be in AppDelegate Or main.m if app has been successfully build and is running and will crash after splash or perhaps the error screen
Issue might be due to use of fonts/resources that is not available with xcode and not properly configured.. You can find out the error by commenting certain portion starting from App.js and drilling inside the navigation/screens and commenting the components till you find the component that is generating the error....
In my case the resource of fontFamily was making an issue which was used right after splash in walkthrough screen
<Text style={{fontFamily: Fonts.roboto}}>ABC</Text>
Here font roboto wasnot configured properly. Wasted entire days just debugging the error hope its helps you
In my case, I was presenting the rootViewController of an UINavigationController when I was supposed to present the UINavigationController itself.
Just remove
[tabBarController presentModalViewController:viewController animated:YES];
and keep
[self dismissModalViewControllerAnimated:YES];
Instead of using:
self.present(viewControllerToPresent: UIViewController, animated: Bool, completion: (() -> Void)?)
you can use:
self.navigationController?.pushViewController(viewController: UIViewController, animated: Bool)
This is my way which supporting multiple Windows(from a single APP) on the iPad and nested modal present.
import UIKit
///✅Use this public method
public func SheetViewController(ViewController:UIViewController) {
for i in returnAvailableViewControllers().shuffled() {
if i.presentedViewController == nil && !ViewController.isViewLoaded {i.present(ViewController, animated: true, completion: {})}
}
}
///Returns all possible ViewControllers
private func returnAvailableViewControllers() -> [UIViewController] {
let 场景 = UIApplication.shared.connectedScenes
var 存储VC : [UIViewController] = []
for i in 场景 {
if i.activationState == .foregroundActive {
//⭐️Set up “foregroundActive” to give the user more control
var 视图控制器 = (i.delegate as? UIWindowSceneDelegate)?.window??.rootViewController
if 视图控制器 != nil {
存储VC.append(视图控制器!)
}
var 结束没 = true
while 结束没 {
//🌟Enumerate all child ViewController
视图控制器 = 视图控制器?.presentedViewController
if 视图控制器 != nil {
存储VC.append(视图控制器!)
} else {
结束没.toggle()
}
}
}
}
return 存储VC
}

UIView is shown displaced to the top

I have a simple app that has two view controllers. Both of them have a UINavigationBar at the top, as a header. The second UIViewController is displayed as a modal view, when the user clicks on a button on the first one.
When my app first launches, the initial view doesn't completely cover the main UIView and seems "pushed" to the top (see image below).
After I click on the "instructions" button, which displays another view with presentModalViewController:animated:, and dismiss the modal ViewController, everything is displayed correctly.
Anybody knows what I might be doing wrong?
I have nothing in viewWillAppear, and this is my viewDidLoad
- (void)viewDidLoad {
[super viewDidLoad];
if (!self.model) {
self.model = [[FRRSushiRiceModel alloc] init];
[[self.header.items objectAtIndex:0] setTitle: #"Perfect Sushi Rice: Ingredients"];
}
}
and my application:didFinishLaunchingWithOptions:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Create and add the main controller (ingredients)
self.ingredientsController = [[FRRIngredientsViewController alloc] init];
[window addSubview:self.ingredientsController.view];
[window makeKeyAndVisible];
return YES;
}
This small project reproduces this behavior:
Test Case
Did you untick the "Wants Full Screen" setting in IB, either for the UINavigationController or UIViewController?
I found the error, guys.
Basically I was trusting the system to correctly set the frame of my views to match the usable portion of the screen. This works when you add it to some controller of controllers (such as UINavigationController), or add it via IB.
If you add your controllers programmatically, you need to set the view's frame explicitly. A good default is:
[[UIScreen mainScreen] applicationFrame]
represents the part of the screen available to applications: the whole screen minus the status bar.