objective-cviewdidloadviewwillappearviewdidappear

Can we only configure UI correctly in viewDidAppear? and not in viewWillAppear/viewDidLoad?


I have a static table view with cells that have a rounded border. I have noticed when testing on different simulators that whilst my auto layout constraints work, the border isn't always the right width. This particular screen consists of a view controller with a UIView containing an embedded tableViewController

I have done some investigating and found that the width of the border actually depends on the width of the storyboard phone. This means if I have a storyboard for an iPhone 8, the 8+ will have cells too short and vice versa, an 8+ storyboard results in cells that are too long (and extend off screen) for the 8.

Currently I am setting the cell borders in the viewDidLoad, here is the code I am using to configure the cells border:

- (void)configureCellThree {
    //Add Border
    CALayer *borderLayer = [CALayer layer];
    CGRect borderFrame = CGRectMake(0, 0, (_contentCellThree.frame.size.width), (_contentCellThree.frame.size.height));
    [borderLayer setBackgroundColor:[[UIColor clearColor] CGColor]];
    [borderLayer setFrame:borderFrame];
    [borderLayer setCornerRadius:_contentCellThree.frame.size.height / 2];
    [borderLayer setBorderWidth:1.0];
    [borderLayer setBorderColor:[kTextColor2 CGColor]];
    // [borderLayer setOpacity:0.5];
    [_contentCellThree.layer addSublayer:borderLayer];
}

Now if I run this code within the viewDidAppear, everything will work across both devices. I added some logs to my main view controller to find out how things were being set.

- (void)viewDidLoad {

    [super viewDidLoad];

    NSLog(@"VDL - SELF.VIEW = %@", self.view);
    NSLog(@"VDL - CONTAINER VIEW = %@", self.profileScrollingContainerView);
}

- (void)viewDidAppear:(BOOL)animated {

    [super viewDidAppear:animated];

    NSLog(@"VDA- SELF.VIEW = %@", self.view);
    NSLog(@"VDA - CONTAINER VIEW = %@", self.profileScrollingContainerView);
}

I had suspected that viewDidLoad was using the sizing information from the storyboard instead of the view itself (which doesn't seem right). This logging confirms this. If I look at the UIView responsible for displaying my tableview, when the storyboard is set to 8+ it has the following frame attributes: X = 0, Y = 349, W = 414, H = 338. Now lets look at the results of the logging:

VDL - SELF.VIEW = <UIView: 0x7fa545401f10; frame = (0 0; 375 667); 
VDL - CONTAINER VIEW = <UIView: 0x7fa545401b50; frame = (0 349; 414 338); 


VDA- SELF.VIEW = <UIView: 0x7fa545401f10; frame = (0 64; 375 603); 
VDA - CONTAINER VIEW = <UIView: 0x7fa545401b50; frame = (0 285; 375 269);

So when the view loads the tableview is getting the wrong information about the views size. When the viewDidAppear gets called it has the correct sizing of the view and will work properly. My issue here is that I don't want to be calling initialising code in my viewDidAppear.

I read here that I should be putting my UI Geometry code into the viewWillAppear however I have tried this and I get the same issues.

VWA - CONTAINER VIEW = <UIView: 0x7fec04d97700; frame = (0 349; 414 338);

So to consolidate my question, How can I get the properties of my view before the view has loaded/appeared so I can correctly setup my UI?

I have read that I will need to subclass UIView and potentially use setFrame however I don't really know how I'd actually go about doing this.


Solution

  • So it turns out I was using the wrong method to do this. I found this question which solved my whole issue. Basically if you need to perform UI calculations (such as adding custom views) you should be performing them in -(void)viewDidLayoutSubviews. This method is called after the view has worked out all of its sizing and constraints so anything you do in here will be executed using the right properties of your view!