title: Why does UIView not stay on centre while it rotates?
body: <p>I am trying to calibrate a UIView to stay on centre as it rotates. This follows up a problem identified by the best answers to <a href="https://stackoverflow.com/a/39950137/2348597">my previous question</a>. I have since devised code based on <a href="https://stackoverflow.com/a/39951619/2348597">one answer</a> proposing to use <code>viewWillAppear</code> or <code>viewDidLayoutSubviews</code> instead of <code>viewDidLoad</code>.</p>
  
  <p>As I am new to Swift I had to revisit the Swift tutorial Implement a Custom Control which describes <a href="https://developer.apple.com/library/content/referencelibrary/GettingStarted/DevelopiOSAppsSwift/Lesson5.html" rel="nofollow noreferrer">how to make a subClass of UIView</a>. My code can draw a circle using any one of three functions: <code>viewWillAppear</code>, <code>viewDidLayoutSubviews</code> or <code>viewDidLoad</code>.</p>
  
  <p>However when I render the code, the circle doesn’t always remain on centre as the screen rotates. Below are successive rotations that happen using <code>viewDidLoad</code> or <code>viewWillAppear</code><a href="https://i.stack.imgur.com/lPEp0.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/lPEp0.png" alt="viewDidLoad or viewWillAppear"></a> When the app is launched on a screen in portrait orientation the problem appears immediately after the first rotation irrespective of left or right. If launched in landscape orientation it is possible to miss a problem if one has not tried at least four successive rotations. </p>
  
  <p>Below are successive rotations that happen using <code>viewDidLayoutSubviews</code> where rotation occasionally results in an on-centre circle overlaying an off-centre circle. <a href="https://i.stack.imgur.com/mm7YA.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/mm7YA.png" alt="viewDidLayoutSubviews"></a> This can happen after several rotations but one must complete at least four rotations in order to notice a problem.</p>
  
  <p>Here is the code for <code>CircleView</code> - my attempt to make a subclass of UIView</p>
  
  <pre><code>import UIKit
  
  class CircleView: UIView {
      let radius          = CGFloat(200)
      let x: CGFloat      = 0
      let y: CGFloat      = 0
  
  // MARK: Initialization
  
  required init?(coder aDecoder: NSCoder) {
      fatalError("init(coder:) has not been implemented")
  }
  
      override init(frame: CGRect) {
      super.init(frame: frame)
      setup()
  }
  
  func setup() {
  
      // Create a CAShapeLayer
      let shapeLayer = CAShapeLayer()
  
      // The Bezier path that we made needs to be converted
      // to a CGPath before it can be used on a layer.
  
      shapeLayer.path = createBezierPath().cgPath
  
      // apply other properties related to the path
  
      shapeLayer.strokeColor      = UIColor.red.cgColor
      shapeLayer.fillColor        = UIColor.white.cgColor
      shapeLayer.lineWidth        = 8.0
  
      // add the new layer to our custom view
      self.layer.addSublayer(shapeLayer)
  }
  
  func createBezierPath() -&gt; UIBezierPath {
      // create a new path
  
      let path  = UIBezierPath(arcCenter: CGPoint(x: x, y: y),
                  radius: radius,
                  startAngle: CGFloat(M_PI * -0.5),
                  endAngle:CGFloat(M_PI * 1.5),
                  clockwise: true)
  
      path.fill()
      path.stroke()
      return path
      } 
  }
  </code></pre>
  
  <p>and here is the code for ViewController</p>
  
  <pre><code>import UIKit
  
  class ViewController: UIViewController {
      var circle: CircleView?
      var x: CGFloat?
      var y: CGFloat?
  
      override func viewDidLoad() {
      super.viewDidLoad()
      let centre = centreCircle()
  
      // create a new UIView and add it to the view controller
      let circleView = CircleView()
      circleView.frame = CGRect(x: centre.x, y: centre.y, width: 0, height: 0)
      view.addSubview(circleView)
      }
  
      func centreCircle() -&gt; CGPoint {
      circle?.bounds = UIScreen.main.bounds
      return CGPoint(x: UIScreen.main.bounds.midX, y: UIScreen.main.bounds.midY)
      }
  }
  </code></pre>
  
  <p>And here is code for the UIScreen extension that returns the screen's centre point</p>
  
  <pre><code>import UIKit
  
  extension UIScreen {
      var centre: CGPoint {
      return CGPoint(x: bounds.midX, y: bounds.midY)
      }
  }
  </code></pre>
  
  <p>To produce the above rotations I replaced <code>viewDidLoad</code> function with <code>viewWillAppear</code></p>
  
  <pre><code>    override func viewWillAppear(_ animated: Bool) {
      super.viewWillAppear(animated)
      let centre = centreCircle()
  
      // create a new UIView and add it to the view controller
      let circleView = CircleView()
      circleView.frame = CGRect(x: centre.x, y: centre.y, width: 0, height: 0)
      view.addSubview(circleView)
      }
  </code></pre>
  
  <p>or <code>viewDidLayoutSubviews</code></p>
  
  <pre><code>    override func viewDidLayoutSubviews() {
      super.viewDidLayoutSubviews()
      let centre = centreCircle()
  
      // create a new UIView and add it to the view controller
      let circleView = CircleView()
      circleView.frame = CGRect(x: centre.x, y: centre.y, width: 0, height: 0)
      view.addSubview(circleView)
      }
  </code></pre>
  
  <p>Can anyone see a problem in my code that might be stopping rotation from working ?</p>