cornerRadius with border: Glitch around border

Here is a Swift 5 version of @CRDave's answer as an extension of UIView:

protocol CornerRadius {
    func makeBorderWithCornerRadius(radius: CGFloat, borderColor: UIColor, borderWidth: CGFloat)
}

extension UIView: CornerRadius {

    func makeBorderWithCornerRadius(radius: CGFloat, borderColor: UIColor, borderWidth: CGFloat) {
        let rect = self.bounds

        let maskPath = UIBezierPath(roundedRect: rect,
                                    byRoundingCorners: .allCorners,
                                    cornerRadii: CGSize(width: radius, height: radius))

        // Create the shape layer and set its path
        let maskLayer = CAShapeLayer()
        maskLayer.frame = rect
        maskLayer.path  = maskPath.cgPath

        // Set the newly created shape layer as the mask for the view's layer
        self.layer.mask = maskLayer

        // Create path for border
        let borderPath = UIBezierPath(roundedRect: rect,
                                      byRoundingCorners: .allCorners,
                                      cornerRadii: CGSize(width: radius, height: radius))

        // Create the shape layer and set its path
        let borderLayer = CAShapeLayer()

        borderLayer.frame       = rect
        borderLayer.path        = borderPath.cgPath
        borderLayer.strokeColor = borderColor.cgColor
        borderLayer.fillColor   = UIColor.clear.cgColor
        borderLayer.lineWidth   = borderWidth * UIScreen.main.scale

        //Add this layer to give border.
        self.layer.addSublayer(borderLayer)
    }

}

I tried many solution and end by using UIBezierPath.

I create category of UIView and add method to make round rect and border.

This is method of that category:

- (void)giveBorderWithCornerRadious:(CGFloat)radius borderColor:(UIColor *)borderColor andBorderWidth:(CGFloat)borderWidth
{
    CGRect rect = self.bounds;
    
    //Make round
        // Create the path for to make circle
        UIBezierPath *maskPath = [UIBezierPath bezierPathWithRoundedRect:rect
                                                       byRoundingCorners:UIRectCornerAllCorners
                                                             cornerRadii:CGSizeMake(radius, radius)];

        // Create the shape layer and set its path
        CAShapeLayer *maskLayer = [CAShapeLayer layer];

        maskLayer.frame = rect;
        maskLayer.path  = maskPath.CGPath;
        
        // Set the newly created shape layer as the mask for the view's layer
        self.layer.mask = maskLayer;
    
    //Give Border
        //Create path for border
        UIBezierPath *borderPath = [UIBezierPath bezierPathWithRoundedRect:rect
                                                         byRoundingCorners:UIRectCornerAllCorners
                                                               cornerRadii:CGSizeMake(radius, radius)];

        // Create the shape layer and set its path
        CAShapeLayer *borderLayer = [CAShapeLayer layer];
        
        borderLayer.frame       = rect;
        borderLayer.path        = borderPath.CGPath;
        borderLayer.strokeColor = [UIColor whiteColor].CGColor;
        borderLayer.fillColor   = [UIColor clearColor].CGColor;
        borderLayer.lineWidth   = borderWidth;
        
        //Add this layer to give border.
        [[self layer] addSublayer:borderLayer];
}

I get idea of using UIBezierPath from this amazing article: Thinking like a Bézier path

I get most of code from this two link:

  • UIView category for rounding just the corners which you want, not all like CALayer cornerRadius.
  • How to get a border on UIBezierPath

Note: This is category method so self represent view on which this method is called. Like UIButton, UIImageView etc.