CGContext drawing in a thread

Guides | Tutorial By 6 years ago

The CGContext provides a great way to draw to the screen on iOS, I use it often to draw custom images. Something that didn’t occur to me initially when I used the UIGraphicsGetCurrentContext() method to obtain a CGContextRef was that it was not thread safe. It was only a few weeks back I drew to a context in a thread, which worked fine sometimes and other times failed. It was obviously a threading problem, and here is the solution.

The UIGraphicsGetCurrentContext() method will give you a reference to the current context. It wont create one, meaning if you use this on a thread and another thread (probably the main thread) uses it at the same time you will get issues. Instead you need to create a context using the CGBitmapContextCreate method, use it and then discard it with CGContextRelease when you’re done. Easy enough, but if you’re creating one yourself you need to know how many bits each colour uses in your colour space, and how many bytes this will be per row. So I don’t need to repeat the exact same code each time to create a CGContextRef, I have made a function you can implement in your project.

CG_INLINE CGContextRef CGContextCreate(CGSize size)
	CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB();
	CGContextRef ctx = CGBitmapContextCreate(nil, size.width, size.height, 8, size.width * (CGColorSpaceGetNumberOfComponents(space) + 1), space, kCGImageAlphaPremultipliedLast);

	return ctx;

Note that this function also complies to Apple’s standard in naming conventions, and will show up when using the analyzer tool if the returned CGContext is never released.

When you want to pull out the UIImage, you can’t use the UIGraphicsGetImageFromCurrentImageContext() function either, you will now need to get the UIImage from a specified context. This is also a few lines you will probably never want to write more than once, so include this function in your project too.

CG_INLINE UIImage* UIGraphicsGetImageFromContext(CGContextRef ctx)
	CGImageRef cgImage = CGBitmapContextCreateImage(ctx);
	UIImage* image = [UIImage imageWithCGImage:cgImage scale:[UIScreen mainScreen].scale orientation:UIImageOrientationUp];

	return image;

Now to create a thread safe image, it’s as simple as

CGContextRef ctx = CGContextCreate(CGSizeMake(100, 100));
CGContextSetFillColorWithColor(ctx, [UIColor redColor].CGColor);
CGContextFillRect(ctx, CGRectMake(0, 0, 100, 100));
UIImage* image = UIGraphicsGetImageFromContext(ctx);

(A 100×100 red square)

  • It’s not a good idea to impinge on Apple’s namespace by prefixing your own functions with CG or UI. Someone unfamiliar with these extensions could think they’re Apple-supported API and wonder why they’re not documented. Apple could also implement their own functions with these names, leading to name collisions and potentially undefined behavior.