Search code examples
iphoneiosuiviewuiviewcontrollerloadview

Where can I specify which UIView is used for the view property of a UIViewController?


I want to set the view property of a UIViewController at runtime. I have an .xib file with two views, and I want my UIViewController subclass that owns the .xib file to decide which UIView to use at runtime. I thought I could do this in loadView by just saying

if(some condition)
    self.view = thisView;
else
    self.view = thatView;

but that didn't work. How can I do this?


Solution

  • If you want to choose your view dynamically, set it inside -[UIViewController loadView]. A word of caution though: calling -[UIViewController view] will call -[UIViewController loadView] if the view hasn't been loaded yet, so if you do this:

    -(void)loadView
    {
        self.view = [[[UIView alloc] initWithFrame:CGRectZero] autorelease];
        self.view.backgroundColor = [UIColor redColor];
    }
    

    The second line of that method will call -loadView, and you'll get infinite recursion (which will lead to a stack overflow, and a crash). You need to setup your view, then set the .view property when you've set it up, like this:

    -(void)loadView
    {
        UIView *newView =  [[[UIView alloc] initWithFrame:CGRectZero] autorelease];
        newView.backgroundColor = [UIColor redColor];
    
        self.view = newView;
    }
    

    So you'll probably want to do something like this:

    -(void)loadView
    {
        UIView *newView = nil;
    
        if (self.theSkyIsBlue) {
            newView = [[[BlueSkyView alloc] initWithFrame:CGRectZero] autorelease];
            newView.backgroundColor = [UIColor blueColor];
        }
        else {
            newView = [[[GraySkyView alloc] initWithFrame:CGRectZero] autorelease];
            newView.backgroundColor = [UIColor grayColor];
        }
    
        self.view = newView;
    }
    

    Addendum 1 - update to show how to use a container view for different views defined in a XIB

    If you want to reference other stuff in your XIB, a better approach is to use your .view as a "container view" for your other views. Set it up in -viewDidLoad, like this:

    - (void)viewDidLoad
    {
        UIView *childView = nil;
        if (someCondition) {
            childView = self.blueView;
        }
        else {
            childView = self.grayView;
        }
        [self.view addSubview:childView];
        childView.frame = self.view.bounds;
    }
    

    Note that if you want to swap your views later on, you should make childView a property, instead of a local variable, so you can remove the old childView when inserting a new one.