I had a similar problem: I need to set the "CALayer" frame when using automatic layout with views (in code, not in IB).
In my case, I had a slightly collapsed hierarchy having a view controller in the view controller. I ended this SO question and reviewed the approach of using viewDidLayoutSubviews . This did not work. Just in case, your situation is similar to mine, that's what I found ...
Overview
I wanted to set the frame for the CAGradientLayer for UIView , which I positioned as a subview inside the UIViewController using the automatic layout restrictions.
Call the subview gradientView and the view controller child_viewController .
child_viewController was a view controller that I would set as a kind of reusable component. Thus, the view of child_viewController was compiled into the parent view controller - this is called parent_viewController .
When viewDidLayoutSubviews of child_viewController was called, the frame of gradientView has not yet been set.
(At this point, I would recommend sprinkling some NSLog statements to get an idea of ββthe sequence of creating views in your hierarchy, etc.)
So, I switched to using viewDidAppear . However, due to the nesting of child_viewController I found that viewDidAppear not called.
(See this SO question: viewWillAppear, viewDidAppear is not called, not fired ).
My current solution
I added viewDidAppear to parent_viewController and from there I call viewDidAppear to child_viewController .
For bootstrap, I need viewDidAppear , as it was until in child_viewController it was called that all subtasks have their frames. Then I can set the frame for CAGradientLayer ...
I said that this is my current decision because I am not very happy with it.
After the initial installation of the CAGradientLayer frame, this frame may become invalid if the layout changes. device rotation.
To handle this, I use viewDidLayoutSubviews in child_viewController - to save the CAGradientLayer frame inside gradientView , fix it.
It works, but does not feel well. (Is there a better way?)