UIViewController returns invalid frame?
ios, landscape, uiviewcontroller
Solution
There are a couple of things that you don't understand.
First, the system sends you `viewDidLoad` immediately after loading your nib. It hasn't even added the view to the view hierarchy yet. So it hasn't resized your view based on the device's rotation either.
Second, a view's frame is in its superview's coordinate space. If this is your root view, its superview will be the `UIWindow` (once the system actually adds your view to the view hierarchy). The `UIWindow` handles rotation by setting the transform of its subview. This mean that the view's frame will not necessarily be what you expect.
Here's the view hierarchy in portrait orientation:
(lldb) po [[UIApp keyWindow] recursiveDescription]
(id) $1 = 0x09532dc0 <UIWindow: 0x9632900; frame = (0 0; 768 1024); layer = <UIWindowLayer: 0x96329f0>>
| <UIView: 0x9634ee0; frame = (0 20; 768 1004); autoresize = W+H; layer = <CALayer: 0x9633b50>>
and here's the view hierarchy in landscape-left orientation:
(lldb) po [[UIApp keyWindow] recursiveDescription]
(id) $2 = 0x09635e70 <UIWindow: 0x9632900; frame = (0 0; 768 1024); layer = <UIWindowLayer: 0x96329f0>>
| <UIView: 0x9634ee0; frame = (20 0; 748 1024); transform = [0, -1, 1, 0, 0, 0]; autoresize = W+H; layer = <CALayer: 0x9633b50>>
Notice that in landscape orientation, the frame size is 748 x 1024, not 1024 x 748.
What you probably want to look at, if this is your root view, is the view's bounds:
(lldb) p (CGRect)[0x9634ee0 bounds]
(CGRect) $3 = {
(CGPoint) origin = {
(CGFloat) x = 0
(CGFloat) y = 0
}
(CGSize) size = {
(CGFloat) width = 1024
(CGFloat) height = 748
}
}
Presumably you want to know when the view's transform, frame, and bounds get updated. If the interface is in a landscape orientation when your view controller loads its view, you will receive messages in this order:
{{0, 0}, {768, 1004}} viewDidLoad
{{0, 0}, {768, 1004}} shouldAutorotateToInterfaceOrientation:
{{0, 0}, {768, 1004}} shouldAutorotateToInterfaceOrientation:
{{0, 0}, {768, 1004}} viewWillAppear:
{{0, 0}, {768, 1004}} shouldAutorotateToInterfaceOrientation:
{{0, 0}, {768, 1004}} shouldAutorotateToInterfaceOrientation:
{{0, 0}, {768, 1004}} willRotateToInterfaceOrientation:duration:
{{0, 0}, {1024, 748}} viewWillLayoutSubviews
{{0, 0}, {1024, 748}} layoutSubviews
{{0, 0}, {1024, 748}} viewDidLayoutSubviews
{{0, 0}, {1024, 748}} willAnimateRotationToInterfaceOrientation:duration:
{{0, 0}, {1024, 748}} shouldAutorotateToInterfaceOrientation:
{{0, 0}, {1024, 748}} viewDidAppear:
You can see that your view's bounds change after you receive `willRotateToInterfaceOrientation:duration:` and before you receive `viewWillLayoutSubviews`.
The `viewWillLayoutSubviews` and `viewDidLayoutSubviews` methods are new to iOS 5.0.
The `layoutSubviews` message is sent to the view, not the view controller, so you will need to create a custom `UIView` subclass if you want to use it.
Problem
When I start my ViewController in `landscape` mode (After viewDidLoad is called), I print the frame it's giving me the frame size for portrait mode instead. Is this a bug any suggestions? ``` - (void)viewDidLoad { [super viewDidLoad]; NSLog(@"%@", NSStringFromCGRect(self.view.frame)); // Result is (0, 0 , 768, 1024) } ```