A helper class for creating icons from a PNG image and colour in Swift
let rect = CGRect(x: 0, y: 0, width: size.width, height: size.height)


can be simplified to

let rect = CGRect(origin: .zero, size: size)


The explicit type annotation in

let backgroundImage: UIImage = UIGraphicsGetImageFromCurrentImageContext()!


is not needed. In

UIGraphicsBeginImageContextWithOptions(size, false, UIScreen.main.scale)


one can pass 0.0 as the last argument, that is also interpreted
as the scale factor of the device’s main screen.

let cornerRadius = newImage.size.height/2
UIBezierPath(roundedRect: bounds, cornerRadius: cornerRadius).addClip()


can be simplified to

UIBezierPath(ovalIn: bounds).addClip()


(and that would work even for a non-quadratic frame).

Instead of creating and drawing into a  bitmap-based graphics context
three times, with two intermediate images, it suffices to use a single graphics context, and


Add a round clipping path,
fill with the given background color,
draw the given image,


all with the same context.

Instead of the fully transparent default icon "iconEmpty.png" you
could make that parameter optional, and draw the icon only if an icon
was provided by the caller.

Finally, the method does not access any properties of the IconMaker
type. You can make it static, so that it can be called without
creating an IconMaker instance:

let newIcon = IconMaker.makeIcon(...)


Putting it all together, the method could look like this:

static func makeIcon(with color: UIColor, size: CGSize, icon: UIImage? = nil) -&gt; UIImage {

    // Create graphics context:
    let rect = CGRect(origin: .zero, size: size)
    UIGraphicsBeginImageContextWithOptions(size, false, 0.0)

    // Circular mask
    UIBezierPath(ovalIn: rect).addClip()

    // Make solid color background:
    color.setFill()
    UIRectFill(rect)

    if let icon = icon {
        // Add other image (which has transparency)
        icon.draw(in: rect, blendMode: .normal, alpha: 1.0)
    }

    // Create new image and release context:
    let newImage = UIGraphicsGetImageFromCurrentImageContext()!
    UIGraphicsEndImageContext()
    return newImage
}


Another option is to use the defer statement for releasing 
the graphics context:

static func makeIcon(with color: UIColor, size: CGSize, icon: UIImage? = nil) -&gt; UIImage {

    // Create graphics context:
    let rect = CGRect(origin: .zero, size: size)
    UIGraphicsBeginImageContextWithOptions(size, false, 0.0)
    defer { UIGraphicsEndImageContext() }

    // ...

    return UIGraphicsGetImageFromCurrentImageContext()!
}


The block passed to the defer statement is executed just before
the function returns. Here it allows to get rid of the newImage
variable. Generally it is a good approach to ensure that all
acquired resources are released properly, no matter how program
control leaves the function.