
Swift Regex Deep Dive
iOS MacOur introductory guide to Swift Regex. Learn regular expressions in Swift including RegexBuilder examples and strongly-typed captures.
One of our engineers was working on a project and wrote some code that crashed when running on a device:
CGColorRef color =
[UIColor colorWithRed: 0.2
green: 0.3
blue: 0.4
alpha: 1.0].CGColor;
[[self.view layer]
setBackgroundColor: color];
It looks reasonable. Could it be a toolkit bug? It’d be weird for something to be so obviously broken in a fundamental CoreAnimation call. It’s like the CGColor
is pointing to garbage when it gets used. Almost as if the newly-created UIColor
suddenly vanished and took the CGColor
down with it.
What could be releasing objects automatically? ARC – that’s its job. From ARC’s point of view, the UIColor
created with -colorWithRed:...
was used to access the CGColor
, and then is no longer needed. The UIColor
wasn’t assigned to anything, therefore ARC decided that the object could be cleaned up at the semicolon at the end of the expression. Therefore it’s a candidate for disposal and got released. The disassembly, viewable in Xcode with Product->Generate Output->Generate Assembly file
, shows that this is the case:
// UIColor colorWithRed:...
blx _objc_msgSend
...
// Hang on to the object, bypassing the autorelease pool
bl _objc_retainAutoreleasedReturnValue
...
// -CGColor
blx _objc_msgSend
...
// The UIColor goes away
bl _objc_release
// and then the layer calls happen
Ordinarily, you’d expect the UIColor
to be in an autorelease pool, and so would survive until the end of the function. In this case, though, you can see ARC’s “avoid the autorelease pool” optimization is being used: if a method returns an autoreleased object, and the caller doesn’t otherwise need to hang on to it, ARC can avoid the trip to the autorelease pool. The method will return a retained object and objc_retainAutoreleasedReturnValue
will dispose of it. That’s why the UIColor
is not kept alive by the autorelease pool.
So how to fix this? One idea we tried was assigning the new UIColor
to a pointer variable, thereby taking it out of that very short-lived expression. After that, get the CGColor
out of it:
UIColor *uicolor = [UIColor colorWithRed: 0.2
green: 0.3
blue: 0.4
alpha: 1.0];
CGColorRef color = uicolor.CGColor;
[[self.view layer] setBackgroundColor: color];
This seems to work – no crashes. Ship it!
Unfortunately, it’s a ticking bomb. The returned UIColor
is being assigned to a strong-reference variable, but it doesn’t get used in the method after extracting the CGColor
. ARC is within its rights to release the object between fetching the CGColor
and setting the layer’s background color. ARC variables are released as soon as the optimizer decides that they are no longer referenced, so the compiler is free to release uicolor after fetching the CGColor
. Current compiler implementations do seem to wait until the end of scope, but that’s not guaranteed. The LLVM Project’s ARC notes say: “By default, local variables of automatic storage duration do not have precise lifetime semantics.”
This means the compiler can do whatever it wants. The currrent Apple LLVM 3.0 compiler releases uicolor
at the end of the method. If the optimizer, either now or in the future, decides that uicolor
’s lifetime is over, it’ll get released.
So, how to fix this? Three Four ways. You can annotate the local variable with the objc_precise_lifetime
attribute if you want it to live til the end of the scope. Update: Thanks to TJ Usiyan for pointing out the NS_VALID_UNTIL_END_OF_SCOPE
foundation wrapper for objc_precise_lifetime
You can explicitly retain the CGColor
so it doesn’t float away, and release it later:
CGColorRef color =
CGColorRetain ([UIColor colorWithRed: 0.2
green: 0.3
blue: 0.4
alpha: 1.0].CGColor);
[[self.view layer] setBackgroundColor: color];
CGColorRelease (color);
The uicolor
is welcome to disappear because the CGColor
will stay around.
You can put in a call to self at the end of the method:
[uicolor self];
And finally you can also bounce through the uicolor
whenever you need its CGColor
. This keeps the variable in use so it won’t be released yet:

 UIColor *uicolor = [UIColor colorWithRed: 0.2
green: 0.3
blue: 0.4
alpha: 1.0];
[[self.view layer] setBackgroundColor: uicolor.CGColor];
Of these, I like the last one better. Less code, less explicit management of object lifespan (which is why we have ARC in the first place), and also makes it very clear from where the CGColor was derived.
_(Thanks to Mike Ash for exploring some of these ARC behaviors with me. Thanks to Juri Pakaste and Dave Dribin for the [uicolor self]
trick.)
_
Our introductory guide to Swift Regex. Learn regular expressions in Swift including RegexBuilder examples and strongly-typed captures.
The Combine framework in Swift is a powerful declarative API for the asynchronous processing of values over time. It takes full advantage of Swift...
SwiftUI has changed a great many things about how developers create applications for iOS, and not just in the way we lay out our...