Search code examples
iosobjective-cuiviewios7viewdidload

UIView is never rendered if added as subview in viewDidLoad


I'm trying to add a subview to a view controller programatically, but it seems like if I add the subview in the viewDidLoad of the view controller whatever I have added as subview in the view itself is not rendered in the view controller.

But if I move the [self.view addSubview:myUIView] in the init method of the view controller, everything is rendered.

Also, if I call the same methods in the viewDidAppear I get all the elements rendered, but it's right after the view controller was displayed, and I can see when the elements are rendered in the view controller.

This would be my view controller:

//interface
@class RLJSignInView;
@protocol RLJSignInViewControllerDelegate;


@interface RLJSignInViewController : UIViewController <UITextFieldDelegate>
@property (nonatomic, readwrite) RLJSignInView *signInView;
@property (nonatomic, assign) id<RLJSignInViewControllerDelegate> delegate;
@end


//implementation
#import "RLJSignInViewController.h"
#import "RLJSignInView.h"
#import "RLJSignInViewControllerDelegate.h"
#import "UIColor+RLJUIColorAdditions.h"


@implementation RLJSignInViewController
- (id)init
{
    self = [super init];

    if (self) {
        _signInView = [[RLJSignInView alloc] initWithFrame:self.view.bounds];

        [self.view addSubview:self.signInView];
    }

    return self;
}
- (void)viewDidLoad
{
    [super viewDidLoad];

    NSLog(@"%@", self.signInView);

    [self.view setBackgroundColor:[UIColor rgbWithRed:250 green:250 blue:250]];
}
@end

And this would be my view:

//interface
@interface RLJSignInView : UIView
@property (strong, nonatomic, readwrite) UITextField *username;
@property (strong, nonatomic, readwrite) UITextField *password;
@property (strong, nonatomic, readwrite) UIButton *signIn;
@property (strong, nonatomic, readwrite) UIButton *signUp;
@end


//implementation
#import "RLJSignInView.h"
#import "UITextField+RLJUITextFieldAdditions.h"
#import "UIButton+RLJUIButtonAdditions.h"


@implementation RLJSignInView
- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];

    if (self) {

        CGRect usernameInputFrame = CGRectMake(10.0, 40.0, self.bounds.size.width - 20, 40);
        CGRect passwordInputFrame = CGRectMake(10.0, 79.0, self.bounds.size.width - 20, 40);
        CGRect signInButtonFrame = CGRectMake(10.0, 160, self.bounds.size.width - 20, 40);
        CGRect signUpButtonFrame = CGRectMake(10.0, 220, self.bounds.size.width - 20, 40);

        UIView *usernameInputLeftView = [[UIView alloc] initWithFrame:CGRectMake(0.0, 0.0, 10.0, 40)];
        UIView *passwordInputLeftView = [[UIView alloc] initWithFrame:CGRectMake(0.0, 0.0, 10.0, 40)];

        self.username = [[UITextField alloc] initWithFrame:usernameInputFrame
                                             textAlignment:NSTextAlignmentLeft
                                                 textColor:[UIColor blackColor]
                                               clearButton:UITextFieldViewModeWhileEditing
                                                  leftView:usernameInputLeftView
                                               placeholder:@"Username"
                                           backgroundColor:[UIColor whiteColor]
                                               strokeWidth:2.0
                                               strokeColor:[UIColor lightGrayColor]
                                              keyboardType:UIKeyboardTypeEmailAddress
                                         byRoundingCorners:UIRectCornerTopLeft | UIRectCornerTopRight
                                               cornerRadii:CGSizeMake(4.0, 4.0)
                                                    secure:NO];

        self.password = [[UITextField alloc] initWithFrame:passwordInputFrame
                                             textAlignment:NSTextAlignmentLeft
                                                 textColor:[UIColor blackColor]
                                               clearButton:UITextFieldViewModeWhileEditing
                                                  leftView:passwordInputLeftView
                                               placeholder:@"Password"
                                           backgroundColor:[UIColor whiteColor]
                                               strokeWidth:2.0
                                               strokeColor:[UIColor lightGrayColor]
                                              keyboardType:UIKeyboardTypeDefault
                                         byRoundingCorners:UIRectCornerBottomLeft | UIRectCornerBottomRight
                                               cornerRadii:CGSizeMake(4.0, 4.0)
                                                    secure:YES];

        self.signIn = [[UIButton alloc] initWithFrame:signInButtonFrame
                                                title:@"Sign In"
                                          colorNormal:[UIColor whiteColor]
                                     colorHighlighted:[UIColor whiteColor]
                                        colorDisabled:[UIColor whiteColor]
                                     backgroundNormal:[UIColor colorWithRed:82 / 255.0 green:156 / 255.0 blue:201 / 255.0 alpha:1.0]
                                         cornerRadius:4.0];

        self.signUp = [[UIButton alloc] initWithFrame:signUpButtonFrame
                                                title:@"Sign Up"
                                          colorNormal:[UIColor blackColor]
                                     colorHighlighted:[UIColor blackColor]
                                        colorDisabled:[UIColor blackColor]
                                     backgroundNormal:[UIColor whiteColor]
                                         cornerRadius:4.0];

        [self addSubview:self.username];
        [self addSubview:self.password];
        [self addSubview:self.signIn];
        [self addSubview:self.signUp];
    }

    return self;
}
@end

I'm not sure what I could do about it, but I know for sure that I would not like the view to be added to the subview on initialisation.

Or maybe I'm doing the rendering of the subviews of the view wrong. I would appreciate some input on this matter if anyone encountered the same thing or if noticed that I messed up something.


Solution

  • Don't call self.view from inside your init method. This will trigger viewDidLoad being called before your init method even returns, which is incorrect behavior.

    Instead, follow this pattern:

    • create your objects (properties / instance variables) in init, or by using lazy instantiation
    • add the subviews in viewDidLoad
    • set the frames in viewWillLayoutSubviews

    This pattern will avoid bugs like the one you posted here, and set you up for success handling rotation and resizing events in the future.