What object is responsible for dipatching the UIViewController
rotation method calls, i.e:
shouldAutorotateToInterfaceOrientation:
willRotateToInterfaceOrientation:duration:
willAnimateFirstHalfOfRotationToInterfaceOrientation:duration:
willAnimateSecondHalfOfRotationFromInterfaceOrientation:duration:
didRotateFromInterfaceOrientation:
I imagine it is UIApplication
(but maybe the AppDelegate or UIWindow).
The next question, is how does the object know which UIViewController
to talk to?
How does it know which UIViewController
has its view as the subview of the window?
Is there a message you can send or a property you can set (of some object) that sets the "Active" UIViewController
for the app?
It seems that UIApplication
is dispatching a message to the active view controller.
But how does your View Controller instance get these messages?
The message is forwarded to the first view controller whose view has been added to the UIWindow
instance.
This boils down to 3 basic scenarios:
The ViewController whose view is
added directly to the UIWindow
instance (single view app)
The navigation Controller in a Navigation based app, then the navigation controller forwards the message to the active views view controller.
The tab bar Controller in a tab bar based app, then the tab bar controller forwards the message to the active views view controller (or the active navigation controller).
The problem you will have, is if you build an app with multiple views, but DO NOT use a Navigation controller or Tab Bar controller. If you swap views in and out of the UIWindow
instance manually, you will not receive these messages reliably.
This is similar to posts like this one:
iPhone viewWillAppear not firing
Just use Apple's conventions for multiple views and you be fine. Hope this saves some one an hour or two
How does it know which UIViewController has its view as the subview of the window?
UIViewController class maintains a static map between views and their view controllers. This map is queried in a few key places inside CocoaTouch. In particular, [UIView nextResponder] queries it and returns the controller if found.
I guess UIWindow does the same lookup with its root view to know which controller to forward rotation events to. Will check this next time I'll be looking something up in the disassembly. (I've spent some time reverse-engineering CocoaTouch to understand how things work there.)
This is all Magic You Don't Ever Worry About. Just add your controller's root view to the window--or get a tab bar or navigation controller to do it for you--and it will receive these messages.
(But if you poke around with the debugger, you might come to the same conclusion I have: there's some sort of internal table mapping each controller's view back to the controller, and the messages are dispatched based on that link.)
Update: This was truly private magic in 2009 when I first wrote this answer, but subsequent changes to iOS have made the APIs behind it public. The root view controller is now accessible through the UIWindow.rootViewController
property, and the tree of descendant view controllers is formed using the UIViewController.childViewControllers
property.
Parent view controllers are responsible for notifying their children of orientation changes. (I'm not sure how the root view controller is notified, but you could set a breakpoint and find out yourself.) The -shouldAutomaticallyForwardRotationMethods
method decides whether UIViewController will do this for you. If it returns NO
, you become responsible for doing so in your -willRotateToInterfaceOrientation:duration:
, -willAnimateRotationToInterfaceOrientation:duration:
, and -didRotateFromInterfaceOrientation:
methods.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With