You can create a custom class, and use a closure to get the updated rect comfortably. Especially handy when dealing with classes (like CAGradientLayer which want you to give them a CGRect):
GView.swift:
import Foundation
import UIKit
class GView: UIView {
    var onFrameUpdated: ((_ bounds: CGRect) -> Void)?
    override func layoutSublayers(of layer: CALayer) {
      super.layoutSublayers(of: layer)
      self.onFrameUpdated?(self.bounds)
    }
}
Example Usage:
let headerView = GView()
let gradientLayer = CAGradientLayer()
headerView.layer.insertSublayer(gradientLayer, at: 0)
    
gradientLayer.colors = [
    UIColor.mainColorDark.cgColor,
    UIColor.mainColor.cgColor,
]
    
gradientLayer.locations = [
    0.0,
    1.0,
]
    
gradientLayer.startPoint = CGPoint(x: 0.0, y: 0.0)
gradientLayer.endPoint = CGPoint(x: 1.0, y: 1.0)
    
headerView.onFrameUpdated = { _ in // here you have access to `bounds` and `frame` with proper values
    gradientLayer.frame = headerView.bounds
}
If you are not adding your views through code, you can set the Custom Class property in storyboard to GView.
Please note that the name GView was chosen as a company measure and probably choosing something like FrameObserverView would be better.