title: Put a mask layer on a UIView of varying size inside UITableViewCell
body: <p>I have a <code>UITableView</code> whose cells contain a subview on which I need to perform three things:</p>
  
  <ol>
  <li>change its width constraint at runtime depending on a value inside an object specific to this cell</li>
  <li>change its background color depending on that same value</li>
  <li>round the top left and bottom left corners of the view but keep the corners on the right hand side as they are (so <code>layer.cornerRadius</code> is not an option)</li>
  </ol>
  
  <p>I use the following code inside my custom <code>UITableViewCell</code> subclass to achieve the rounded corner effect on one side of the view only, which I call from <code>tableView:cellForRowAt:</code>:</p>
  
  <pre><code>func roundLeadingEdgesOfBar() {
      let roundedLayer = CAShapeLayer()
      roundedLayer.bounds = viewInQuestion.frame
      roundedLayer.position = viewInQuestion.center
      roundedLayer.path = UIBezierPath(roundedRect: viewInQuestion.bounds,
                                       byRoundingCorners: [.topLeft, .bottomLeft],
                                       cornerRadii: CGSize(width: 2, height: 2)).cgPath
      viewInQuestion.layer.mask = roundedLayer
      print("frame: \(viewInQuestion.frame)")
  }
  </code></pre>
  
  <p>However what I see when I run this code is an effect like this:
  <a href="https://i.stack.imgur.com/qPGcA.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/qPGcA.png" alt="enter image description here"></a></p>
  
  <p>The <code>print</code> statement in the code above produces the following output, indicating that <code>viewInQuestion</code> has the same frame every time when clearly on the screen it hasn't:</p>
  
  <pre><code>frame: (175.0, 139.5, 200.0, 5.0)
  frame: (175.0, 139.5, 200.0, 5.0)
  frame: (175.0, 139.5, 200.0, 5.0)
  frame: (175.0, 139.5, 200.0, 5.0)
  </code></pre>
  
  <p>So I assume the width constraint on the view has not been rendered by the time I call this function. When I scroll the entire table view up until all cells are out of view, and then scroll them back into view, everything looks correct and the printed frames are all different, like I would expect:</p>
  
  <pre><code>frame: (136.5, 79.5, 238.5, 5.0)
  frame: (169.5, 79.5, 205.5, 5.0)
  frame: (226.0, 79.5, 149.0, 5.0)
  frame: (247.5, 79.5, 127.5, 5.0)
  </code></pre>
  
  <p>I've read several times on SO to execute code that is dependent on constraints having been applied from within <code>layoutSubviews</code>, but that gave me the same result. I even tried calling <code>roundLeadingEdgesOfBar</code> from within <code>tableView:willDisplay:forRowAt:</code>, to no avail.</p>
  
  <p>I also found <a href="https://stackoverflow.com/a/29638701/1722704">this response to a similar problem</a> which suggests putting the mask layer code inside <code>drawRect:</code>. This actually fixes 99% of the problem for me (leaving performance issues aside), but there are still corner cases (no pun intended) left for very long table views where I still see the wrong behavior.</p>
  
  <p>My last resort was to call my rounding function via <code>performSelector</code> with a 0.00001 delay, which works in the sense that you see the bug for about a second on screen before it then disappears - still far from ideal behavior, let alone the awful code I had to write for it.</p>
  
  <p>Is there any way to reliably apply the shape layer on the view inside a <code>UITableViewCell</code> using its correct runtime frame?</p>