Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ViewWillAppear not getting called with UISplitViewController

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

like image 216
S B Avatar asked Oct 25 '11 13:10

S B


2 Answers

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.

like image 110
ACBurk Avatar answered Sep 21 '22 12:09

ACBurk


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.

like image 41
aopsfan Avatar answered Sep 25 '22 12:09

aopsfan