My application starts off with nothing but a UIWindow. I programmatically add a view controller to self.window in application:didFinishLaunchingWithOptions:.
myViewController = [[UIViewController alloc] init:...];
...
[self.window addSubview:myViewController.view];
[self.window makeKeyAndVisible];
At the same time i kick off a background process:
[NSThread detachNewThreadSelector:#selector(startupOperations) toTarget:self withObject:nil];
The startupOperations look something like this:
NSAutoreleasePool *threadPool = [[NSAutoreleasePool alloc] init];
// Load data
...
// When your done, call method on the main thread
[self performSelectorOnMainThread:#selector(showMainViewController) withObject:nil waitUntilDone:false];
// Release autorelease pool
[threadPool release];
showMainViewController removes myViewController, creates a UITabBarController and sets it as the window's main view:
[self.myViewController.view removeFromSuperview];
self.myViewController = nil;
tabBarController = [[UITabBarController alloc] init];
...
[self.window addSubview:tabBarController.view];
[self.window makeKeyAndVisible];
Questions:
All the view controllers are returning YES for shouldAutorotateToInterfaceOrientation:. Rotation works fine for myViewController but as soon as the tabBarController is made visible, rotation stops working and interface appears in Portrait. What's the reason behind this behavior?
Also, in iOS 4.x, UIWindow has rootViewController property. What's the role of this property? The new templates use rootViewController instead of [self.window addSubview:...]. Why is that?
Pretty strange. I tried and simulate your "view flow" in a simple tab bar based project and autorotation effectively works after removing the initial controller and adding the tab bar controller's view as a subview.
The only condition I found where it did not work is when self.window did contain a second subview that I did not remove. Could you check at the moment when you execute
[self.window addSubview:tabBarController.view];
what is self.window.subview content?
If that does not help, could you share in your question how you initialize the UITabBarController and UITabBar?
As to your second question, as you say rootViewController is the root controller for all the views that belong to the window:
The root view controller provides the content view of the window. Assigning a view controller to this property (either programmatically or using Interface Builder) installs the view controller’s view as the content view of the window. If the window has an existing view hierarchy, the old views are removed before the new ones are installed.
(Source)
You can also use that, but take care of assigning it already in applicationDidFinishLaunching, otherwise, if you "manually" add a subview and later change this property, it will not remove the subview you explicitly added.
Related
Im starting to learn OC.
The first question is about _window.rootviewcontroller and [_window addSubview:...]
Both of the two ways can set view for UIWindow (actually, UIWindow is inherited from UIView).
So what I want to know is :
Is setting the rootviewcontroller for window just using the addSubview method to implement , or it's something else?
more exactly:
is
_window.rootviewcontroller = viewController;
meaning
[_window addSubview: viewController.view];
or
_window = viewController.view; //UIWindow : UIView
or something else?
Thanks a lot.
Is there anyone who can tell me some details about UIWindow and the rootViewController property?
If you use addSubview: to have to pass a UIView instance but when you call rootviewcontroller you passing UIViewController instance to the UIWindow.
You can use addSubview but you have to associate UIView superview (Which needs to be UIViewController) to the UIWindow, to make it behave the same,
something like that (old way to to that:
[window addSubview:myViewController.view];
[window makeKeyAndVisible];
By using rootviewcontroller it will do it for you.
This is taken from Apple:
The root view controller provides the content view of the window.
Assigning a view controller to this property (either programmatically
or using Interface Builder) installs the view controller’s view as the
content view of the window. If the window has an existing view
hierarchy, the old views are removed before the new ones are
installed.
Obviously not. The root view controller is generally assigned to window in appdelegate class.
Also, root view controller is always associated with UINavigationController. So that any root view controller of a UINavigationController will be a its content view controller.
Where as, add subview is just a method of UIView class. Which helps to add any subview to the respective view.
I have a main view controller using a navigation controller and i was making my application over that. Now i want to add a welcome view controller for my app and make it show first instead of my main view controller. Is there any way to do it.
What I did was adding a view controller to my storyboard and added two classes of the same name then i made it my root view controller and unchecked the root view controller from the main view but it is not showing on the window. Please help me, that how can i make my welcome view to appear before the main view controller. Thanks
Inside Interface Builder, under the attributes section (looks like a small slider) about a quarter of the way down the list of settings, there is a section labeled "View Controller." The second item in that section is a checkbox "Is Initial View Controller," check that box and you should see the starting arrow of the story board move to the specified view controller and the app should launch to that page.
Hope this Helps.
You could do this programmatically by setting the app window's rootViewController. From the app delegate's application:didFinishLaunchingWithOptions:
- (BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
UIScreen *mainScreen = [UIScreen mainScreen];
self.window = [[KTAppWindow alloc] initWithFrame:mainScreen.bounds];
[window makeKeyAndVisible];
window.rootViewController = [[WelcomeViewController alloc] init];
return YES;
}
Then you just need to set up your trigger to switch from the Welcome view to the main view. This could be scheduling an NSTimer, for example. Whatever the trigger is, once it occurs just change the window's rootViewController instance to your MainViewController.
I hope this helps.
It calls "Splash Screen" you just need to add a new ViewController in your Storyboard or if you don't have a Navigation Controller add.
In the Splash class, in the viewDidLoad method you need to put this:
UIStoryboard *sb = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
HomeViewController *vc = [sb instantiateViewControllerWithIdentifier:#"Home"];
[[[[UIApplication sharedApplication] delegate] window] setRootViewController:vc];
[self performSegueWithIdentifier:#"Home" sender:self];
here you can add conditions if you needed
I am developing an iOS app and using storyboards. In my storyboard, I had set a view controller as the initial view controller. Everything working fine.
Now I have to write some login in app delegate to decide which view controller to show at the beginning because this depends on how far the user is in the login process.
So, I removed the initial view controller mark from my storyboard and removed the storyboard setting from my plist file.
Now, in the app delegate I have this code -
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"Main" bundle:[NSBundle mainBundle]];
UIViewController *initialViewController = [storyboard instantiateViewControllerWithIdentifier:[XYZUtils getStartScreenViewController]];
XYZStartScreenViewController *startScreenViewController = (XYZStartScreenViewController *)initialViewController;
[self.window addSubview:startScreenViewController.view];
[self.window setRootViewController:startScreenViewController];
[self.window setBackgroundColor:[UIColor whiteColor]];
[self.window makeKeyAndVisible];
This does not display the view controller - I am just getting a black screen and no error messages. On using breakpoints to walk through the above code, there is no error. The view controller is being instantiated but it is not getting displayed.
Am I missing something here?
Read this post..
It is better you make an empty view controller and mark that as initial view controller
And do all login process in that view controller's viewDidLoad method.
Linking a new viewcontroller to Storyboard?
For some reason, when you deselect the initial view controller setting in the storyboard, then your app will not get a UIWindow setup in didFinishLaunching.
So, what you should so is instantiate your own window there; just add this to the beginning of your application didFinishLaunchingWithOptions method:
UIWindow* window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
I think this solution is perfectly fine, but a "cleaner" one since you are using the storyboard, is having some sort of "LoginManagerViewController" as your initial view controller with the responsibility of handling where to do next based on how far the user is in the login process.
I want to stack a UIViewController Board on top of a UIViewController Menu in order to create a Facebook-like side menu. This menu should contain a UITextView.
So far I can drag the Board View side ways and the Menu appears underneath it. Great. But there's an issue with the UITextView inside the menu. When I click it the app crashes with a BAD_EXC... exception. It seems like an issue with the UITextView Delegate.
Here's how I currently set it.
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
//Board
board = [[BoardViewController alloc] init];
[self.window setRootViewController:board];
//Menu
MenuViewController* menu = [[MenuViewController alloc]init];
menu.textView.delegate = menu;
[self.window addSubview:menu.view];
//Window
self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
return YES;
}
Note: when I set the textView delegate to board and implement the delegate methods there it works but that really seems to be the wrong place to implement the menu textview methods to me. The delegate of the menu should be in the menu class itself.
How to set the menu's textView delegate correctly to the menu class?
//Menu
MenuViewController* menu = [[MenuViewController alloc]init];
menu.textView.delegate = menu;
[self.window addSubview:menu.view];
And then, poof: the menu view controller isn't referenced again and is deallocated by ARC. The view is retained by the window so it will look like everything is ok until the text view tries to send its delegate message to an object which was long since deallocated. This is the cause of your EXC_BAD_ACCESS crash.
The simple, slack solution would be to define a property in your app delegate for the menu view controller.
#property (nonatomic, strong) MenuViewController * menu;
and then store the menu there
//MenuViewController* menu = [[MenuViewController alloc]init];
//becomes
self.menu = [[MenuViewController alloc]init];
The proper solution and the one I recommend is that you look up UIViewController containment and implement your own custom view controller container that looks after this special arrangement of view controllers.
Just to briefly outline: You would have a subclass of UIViewController with two properties, one for the board view controller and one for the menu view controller. It would have a scroll view and would be responsible for the sliding action and any communication that needed to be passed from the board to the menu and vis versa. This container would also be responsible for loading the board and the menu view controllers and inserting their views into the correct places in its own view. If the board view controller needs to be swapped out for another board then the container would be responsible for this also.
You would usually set that by dragging the delegate connection from the textField to the view controller in interface builder, or programmatically in viewDidLoad of the menu view controller. You're right in that your app delegate shouldn't have anything to do with this process.
I'm working on adopting slide (split) view controller to my project.
JT, DD, ZUUI, JW, ECS.....
All these sources suggesting initialize my root view controller in appDelegate.
Something like this....
MyMainViewController *controller = [MyMainController alloc] init];
UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:Controller];
.........
self.window.rootViewController = viewController;
[self.window makeKeyAndVisible];
Problem is I can't make my view visible, my app show blank page only with a empty navigation bar.
I customized my main view using AQGrid, is this causing a problem?
My view looks different to storyboard look. (because I customized it.)
So when I do initialize I'm using "self.storyboard initialize......method".
But in appdelegate, I can't use that method.
Simply, I can't make this view hierarchy because when I initialize my view it is not visible.
ZUUIRevealController is parent of:
UINavigationController is parent of:
FrontViewController
If you are using a storyboard, don't do any of that. Instead, choose your starting view controller from the storyboard and check the "Is Initial View Controller" in the Attributes inspector.