Understanding the Rotation Methods in UIViewController: The Role of UIApplication

Understanding the Rotation Methods in UIViewController

The UIViewController class provides several methods to handle rotation, including shouldAutorotateToInterfaceOrientation:, willRotateToInterfaceOrientation:duration:, willAnimateFirstHalfOfRotationToInterfaceOrientation:duration:, willAnimateSecondHalfOfRotationFromInterfaceOrientation:duration:, and didRotateFromInterfaceOrientation:. But who is responsible for dispatching these method calls? And how does the UIViewController instance know which one to respond to?

The Role of UIApplication

According to Apple’s documentation, it is indeed the UIApplication class that is responsible for forwarding messages related to rotation to the active view controller.

{< highlight objective-c >}
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation duration:(NSTimeInterval)duration {
    // ...
}

In this code snippet, you can see how the UIApplication class is dispatching a message when the interface orientation is about to change.

But how does the view controller instance receive these messages?

The Active View Controller

The answer lies in the concept of an “active” view controller. The UIApplication class maintains an internal state that keeps track of which view controller has its view added to the UIWindow instance.

{< highlight objective-c >}
// In UIApplication.m:
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation duration:(NSTimeInterval)duration {
    // ...

    // Get the active view controller
    UIViewController *activeViewController = [self activeViewController];

    // Forward the message to the active view controller
    [activeViewController willRotateToInterfaceOrientation:interfaceOrientation duration:duration];
}

In this code snippet, you can see how the UIApplication class is retrieving the active view controller before forwarding a message related to rotation.

Scenarios for View Controllers

There are three basic scenarios in which a view controller might receive these messages:

1. Single View App

In a single-view app, the view controller whose view is added directly to the UIWindow instance will receive the messages related to rotation.

{< highlight objective-c >}
// In ViewController.m:
- (void)viewDidLoad {
    // ...

    // Add the view to the UIWindow instance
    [[UIApplication sharedApplication] setMainWindow:[[UIWindow alloc] initWithScreenSize:UIRectMake(0, 0, [UIScreen mainScreen].bounds.size.width, [UIScreen mainScreen].bounds.size.height)]];
}

In this code snippet, you can see how a single-view app adds its view to the UIWindow instance and receives messages related to rotation.

2. Navigation Controller

In a navigation-based app with a navigation controller, the active view controller will receive the messages related to rotation.

{< highlight objective-c >}
// In NavController.m:
- (void)viewDidLoad {
    // ...

    // Set the main window
    [[UIApplication sharedApplication] setMainWindow:self.window];
}

// In UIViewController.m:
- (void viewDidLoad {
    // ...

    // Get the navigation controller
    UINavigationController *navigationController = [self navigationController];

    // Forward the message to the active view controller
    [navigationController.activeViewController willRotateToInterfaceOrientation:navigationController.interfaceOrientation duration:0];
}

In this code snippet, you can see how a navigation-based app sets its main window and receives messages related to rotation.

3. Tab Bar Controller

In a tab bar-based app with a tab bar controller, the active view controller will receive the messages related to rotation.

{< highlight objective-c >}
// In TabBar.m:
- (void)viewDidLoad {
    // ...

    // Set the main window
    [[UIApplication sharedApplication] setMainWindow:self.window];
}

// In UIViewController.m:
- (void viewDidLoad {
    // ...

    // Get the tab bar controller
    UITabBarController *tabBarController = [self tabBarController];

    // Forward the message to the active view controller
    [tabBarController.activeViewController willRotateToInterfaceOrientation:tabBarController.interfaceOrientation duration:0];
}

In this code snippet, you can see how a tab bar-based app sets its main window and receives messages related to rotation.

Conclusion

The UIViewController class provides several methods to handle rotation, but who is responsible for dispatching these method calls? According to Apple’s documentation, it is indeed the UIApplication class that is responsible. The view controller instance receives these messages by being registered as the active view controller in the UIWindow instance.

By understanding how the UIApplication class forwards messages related to rotation, developers can create apps with multiple views and ensure that their app responds correctly to changes in interface orientation.

Troubleshooting

One common issue that developers may encounter is when swapping views in and out of the UIWindow instance manually. In this case, the view controller will not receive the messages related to rotation reliably.

To avoid this problem, it is recommended to use Apple’s conventions for multiple views, such as using a navigation controller or tab bar controller to manage multiple views.

By following these guidelines, developers can create apps that respond correctly to changes in interface orientation and provide a seamless user experience.


Last modified on 2023-08-12