I want to expand and contract a circle using CABasicAnimation. I previously designed a clean and effective way to draw the animation using sin and the drawRect method of the UIView class, but unfortunately it seems you can't animate or force drawRect to fire in UIView.animate methods no matter what you do. Therefore, I've had to come up with a workaround using CABasicAnimation. The result kind of works, but the animation is ugly and doesn't look right. Here's an illustration of what I mean: 
Warping occurs during the expansion and contraction, and there appears to be a dent or cavity on the right side when the circle is expanding. Here's the class responsible for animating it:
struct PathConfig {
    var arcCenter: CGPoint
    var radius: CGFloat
    let startAngle: CGFloat = 0.0
    let endAngle: CGFloat = CGFloat(2 * M_PI)
}
class RGSStandbyIndicatorView: UIView {
    // MARK: - Variables & Constants
    /// The drawing layer.
    var shapeLayer: CAShapeLayer!
    // MARK: - Class Methods
    /// Animation function.
    func animate(period: CFTimeInterval) {
        let p: PathConfig = PathConfig(arcCenter: CGPoint(x: frame.width / 2, y: frame.height / 2) , radius: 17.5)
        let b: UIBezierPath = UIBezierPath(arcCenter: p.arcCenter, radius: p.radius, startAngle: p.startAngle, endAngle: p.endAngle, clockwise: true)
        let a: CABasicAnimation = CABasicAnimation(keyPath: "path")
        a.fromValue = shapeLayer.path
        a.toValue = b.cgPath
        a.autoreverses = true
        a.duration = period
        a.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut)
        a.repeatCount = HUGE
        shapeLayer.add(a, forKey: "animateRadius")
    }
    /// Initializes and returns a CAShapeLayer with the given draw path and fill color.
    private class func shapeLayerForPath(_ path: CGPath, with fillColor: CGColor) -> CAShapeLayer {
        let shapeLayer: CAShapeLayer = CAShapeLayer()
        shapeLayer.path = path
        shapeLayer.fillColor = fillColor
        return shapeLayer
    }
    /// Configures the UIView
    private func setup() {
        // Init config, path.
        let cfg: PathConfig = PathConfig(arcCenter: CGPoint(x: frame.width / 2, y: frame.height / 2) , radius: 0.0)
        let path: UIBezierPath = UIBezierPath(arcCenter: cfg.arcCenter, radius: cfg.radius, startAngle: cfg.startAngle, endAngle: cfg.endAngle, clockwise: true)
        // Init CAShapeLayer
        shapeLayer = RGSStandbyIndicatorView.shapeLayerForPath(path.cgPath, with: UIColor.white.cgColor)
        layer.addSublayer(shapeLayer)
    }
    // MARK: Class Method Overrides
    override init(frame: CGRect) {
        super.init(frame: frame)
        setup()
    }
    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        setup()
    }
}
I've tried adjusting the start and end angles hoping it was some artifact of the path having no overlap, but it didn't change anything. I'm not sure how to fix this problem, and It's based off Chadwick Wood's answer to a similar question.
