How to draw images programmatically without Views or UIViews for your Tests

Daniel Torres
2 min readJun 12, 2022

--

Would you like to gain some performance in your tests by drawing images without needing a UIViewController, UIView, or Views? This article shows how to draw a tiny square image using UIGraphicsImageRenderer without using an UIView/View and in any thread.

Because loading images locally using XCAssets can hit the performance of your tests by reading data from disk. It is better to use in-memory images so we don’t have to read from disk and not depend on name assets that might not be there when reading them.

Previously we would use UIGraphicsBeginImageContext like this:

let rect = CGRect(x: 0, y: 0, width: 1, height: 1)
UIGraphicsBeginImageContext(rect.size)
let context = UIGraphicsGetCurrentContext()!
context.setFillColor(color.cgColor)
context.fill(rect)
let img = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()

But this will force you to manage Core Graphics contexts. i.e. you need to begin drawing the image using UIGraphicsBeginImageContext context and finish it using UIGraphicsEndImageContext. This creates a bitmap-based graphics where the image will be drawn. The size measured in points it receives represents the size of the image returned by the `UIGraphicsGetImageFromCurrentImageContext`.

While this is pretty straightforward, there are a couple of things that can be improved like:

  1. You must manage the created core graphics context in the same scope.
  2. You need to get the underlying UIImage’s data to get a png or jpeg version of the image.

Introducing UIGraphicsImageRenderer! with this new class, you can quickly draw your image specifying the size measured in points in a closure-based message call like this.

let imageSize = CGSize(width: 1, height: 1)
let renderer = UIGraphicsImageRenderer(size: imageSize)
let imagePngData = renderer.pngData { (context) in
color.setFill()
context.fill(.init(origin: .zero, size: imageSize))
}
return UIImage.init(data: imagePngData)!

This way, you don’t have to manage your core graphics context for the image, and you can get access to an UIImage object, to its png or jpeg data version using: image(actions:), jpegData(withCompressionQuality:actions:) , pngData(actions:) respectively.

UIGraphicsImage renderer is thread-safe. If you like to use custom drawing to your bit map, you can use the available API’s from the received CGContext class.

References:
UIGraphicsImageRenderer

UIGraphicsBeginImageContextWithOptions function

Would you like to become an excellent iOS developer that thrives in any situation given? check out this website: Essential Developer

--

--

Daniel Torres
Daniel Torres

Written by Daniel Torres

iOS developer - Delivering exceptional results no matter the situation.