Background & Objective: I have a UISplitViewController based iPad app - till now it supported 4 orientations but now I want to lock it down to only landscape.
I changed shouldAutorotateToInterfaceOrientation of the left view controller to support only landscape mode, but this stops its viewWillAppear from getting called.
Details: My iPad's view controllers are organized as below:
window
`-- splitVC (UISplitViewController)
    `-- rootNav (UINavigationController)
        `-- hvc (HostManagerViewController, derived from UIViewController)
    `-- detailViewController (DetailViewController, derived from UIViewController)
This is implemented in the App Delegate as below:
- (BOOL)application:(UIApplication *)application
         didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    HostManagerViewController *hvc  = [[[HostManagerViewController alloc]
                                       initWithNibName:nil bundle:nil] autorelease];
    self.detailViewController = [[[DetailViewController alloc]
                                initWithNibName:nil bundle:nil] autorelease];
    UINavigationController *rootNav = [[[UINavigationController alloc]
                                        initWithRootViewController:hvc] autorelease];
    UISplitViewController *splitVC= [[[UISplitViewController alloc] init] autorelease];
    [splitVC setViewControllers:[NSArray arrayWithObjects:rootNav,
                                 detailViewController, nil]];
    splitVC.delegate = detailViewController;
    [window addSubview:splitVC.view];
    [window setRootViewController:splitVC];
    return YES;
}
viewWillAppear gets called when both DetailViewController.m and HostManagerViewController.m contain
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
    return YES;
}
Console output:
Should rotate called to hostmanager with 1
Should rotate called to hostmanager with 1
Should rotate called to hostmanager with 1
Should rotate called to hostmanager with 3
Hostmanager: Viewdidload
Should rotate called to hostmanager with 1
Hostmanager: viewwillappear
But when I change HostManagerViewController's code to
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
    return (UIInterfaceOrientationIsLandscape(interfaceOrientation));
}
then 'viewWillAppear` of HostManagerViewController is not invoked. Console output
Should rotate called to hostmanager with 1 (1 is the numeric value of interfaceOrientation)
Should rotate called to hostmanager with 1
Should rotate called to hostmanager with 1
Should rotate called to hostmanager with 1
Should rotate called to hostmanager with 3
Should rotate called to hostmanager with 3
Should rotate called to hostmanager with 1
Should rotate called to hostmanager with 1
Should rotate called to hostmanager with 1
Should rotate called to hostmanager with 3
Should rotate called to hostmanager with 1
Should rotate called to hostmanager with 1
Should rotate called to hostmanager with 1
Should rotate called to hostmanager with 3
Should rotate called to hostmanager with 1
Should rotate called to hostmanager with 1
Should rotate called to hostmanager with 1
Should rotate called to hostmanager with 3
Hostmanager: Viewdidload
Should rotate called to hostmanager with 1
Only Landscape modes are supported in the Info.plist
EDIT: Inserted NSLog messages to track shouldAutorotateToInterfaceOrientation, viewWillAppear and ViewDidLoad
I asked what iOS version you were using because I tried to create a simple reproduction of your problem and found the behavior differs between 4.3 and 5.0. It actually does make all the correct calls in 5.0. I believe this to simply be a bug with the UISplitviewController. Splitview controller was quite buggy. aopsfan's answer does not solve the problem (I have confirmed this). I would suggest subclassing uisplitviewcontroller, and overriding the splitview controller's viewwillappear, viewdidappear like so:
#import "testSplitViewController.h"
@implementation testSplitViewController
-(void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];
    NSString *reqSysVer = @"5.0";
    NSString *currSysVer = [[UIDevice currentDevice] systemVersion];
    if ([currSysVer compare:reqSysVer options:NSNumericSearch] == NSOrderedAscending)
        [[[self viewControllers] objectAtIndex:0] viewWillAppear:animated];
}
-(void)viewDidAppear:(BOOL)animated {
    [super viewDidAppear:animated];
    NSString *reqSysVer = @"5.0";
    NSString *currSysVer = [[UIDevice currentDevice] systemVersion];
    if ([currSysVer compare:reqSysVer options:NSNumericSearch] == NSOrderedAscending)
        [[[self viewControllers] objectAtIndex:0] viewDidAppear:animated];
}
@end
You have to check the version number so that you don't make the viewDidAppear call twice.
Or just go with 5.0 or above if you can, since the bug seems to be fixed.
Basically, since a UISplitViewController has two parts, you need a universal implementation of shouldAutorotate.  I suppose that tackling the rotation of the view controllers individually can cause some weird side affects--though please take note that I was not able to replicate your viewWillAppear issue, so this solution is really a guess.
I would recommend making a dead-simple subclass of UISplitViewController.  Name it "SplitViewController", and in it's .m file, delete everything except shouldAutorotate, which will look like this:
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
    return (UIInterfaceOrientationIsLandscape(interfaceOrientation));
}
Now change your shouldAutorotate code in HostManagerViewController and DetailViewController back to:
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
    return YES;
}
Now, in your app delegate, use this class instead of UISplitViewController. This should (may) fix your problem.
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