Objective-C is a really cool programming language that is designed for Mac OSX and iOS software development. TIOBE has announced November Haedline: Objective-C on its way to become “language of the year” again. It is popular not only because the platform, but also its great performance on mobile devices. Objective-C featured in its manually memory management instead of garbage collection. Yet, its not that manual in modern Objective-C. Apple introduced Automatic Reference Counting, ARC, that inserts memory management code for you on compile time. In most cases of Objective-C development, it JUST WORKS. However, it is often confusing when you mix ARC code with Core Foundation objects (low level C references on apple’s platform). Today, I’ll talk about pitfalls and concepts of ARC especially when gluing CF objects with toll-free bridging.
Daily ARC
I’ll first make a quick go through of ARC in two major uses: Objective-C properties and ARC type qualifiers. Then we’ll cut deep into memory management of Core Foundation Framework.
ARC and Objective-C properties
It is really hard to write a new article about ARC without @amattn’s collection of ARC Best Practices. You can find the complete best practices there, and below link is my highlight of his article 1:
Expand my highlight of ARC best pracitices by @amattn
ARC specific type qualifiers
About type qualifier rules, you can see my previous post. There are four ARC specific type qualifiers introduced by Apple:
__strong
is the default. An object remains alive as long as there is a strong pointer to it.__weak
specifies a reference that does not keep the referenced object alive. A weak reference is set tonil
when there are no strong references to the object.__unsafe_unretained
specifies a reference that does not keep the referenced object alive and is not set tonil
when there are no strong references to the object. If the object it references is deallocated, the pointer is left dangling.__autoreleasing
is used to denote arguments that are passed by reference(id *)
and are autoreleased on return.
Beware that ARC type qualifiers are used for POINTER TYPE. That is, you must put the qualifier at the right hand side of the star.
1 2 3 4 5 6 7 8 9 |
|
You might wonder that there is so many wrong format on the internet. But [Apple officially] said so:
You should decorate variables correctly. When using qualifiers in an object variable declaration, the correct format is:
ClassName * qualifier variableName;
ARC and toll-free bridging
The biggest problem of ARC occurs when you mix it with Core Foundation references. The rules of thumb are
- When you transfer an Objective-C object to a CF reference, you retain it.
- When you transfer a CF reference to an Objective-C object, you release it.
- It is dangerous if you didn’t change ownership of objects. Sometimes Clang corrects it for you, sometimes don’t.
- There is no autorelease in Core Foundation, and you must follow the Core
Foundation memory management naming convention:
- Those object returned from function with
Create
orCopy
, you own the object, thus you must release it. - If the function name contains the word
Get
, you do not own the object. Do not release it.
- Those object returned from function with
There are two ways to retain a CF object: a type casting like syntax
(__bridge_retained)
or C function CFBridgingRetain
. Though clang show up
diagnostics to use the former syntax, I prefer to use the latter one because it
is easier to read for me.
1 2 3 4 |
|
When you get an object from Core Foundation with name containing Create
or
Copy
, use (__bridge_transfer)
or CFBridgingRelease
.
1 2 3 4 5 |
|
Pitfalls in toll-free bridging
When you see a code like this:
1 2 3 4 |
|
Beware! It might crash at any time. Since we do not hold the reference of UIColor, it would be released right after you create it! The CGColor it owns would be released as well and thus cause a crash. There are three ways to fix it:
- Use
__autorelease
type qualifier. UIColor would be released at the end of current run loop. It can fix the crash. I believe @amattn is the first one who discovered this solution.
1 2 3 4 |
|
- Use Core Foundation naming convention and change the owner ship to the receiver.
1 2 3 4 5 6 7 8 9 10 |
|
- Owns the CF object by self. If self is dealloced, the reference would still cause a crash.
1 2 3 4 |
|
Pitfalls in block and ARC
When you use a ivar in self owned block, it will implicitly contain self in your block and thus cause a retain cycle:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
The only way to implement this safely is to use weak reference of self, and setup a strong reference to weak self only in the scope of this block. The reason we need to use a strong reference in scope is weak reference can be zero out at any time. We must claim we own the object when we are using it.
1 2 3 4 5 6 7 8 9 10 |
|
Pitfalls in NSError
If you are implementing methods that take NSError, be sure to use the correct format of type qualifier!
1 2 |
|
Actually, when you craete a NSError object, it is always best to declare it is an autoreleasing object:
1 2 3 |
|
Summary
ARC is handy, but not easy. When you facing complex memory ownership model, wrting some testing code to know how retain count being managed is still a recommanded pactice. The below snippet is how I test retain count when mixing CF object, block, and objective-c object:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
|
Hope these helps! Comments and sharing are welcome!
-
I didn’t reference back to @amattn’s ARC best practices when I first post this article. I am really sorry that I didn’t do it and I really appreciate his pioneer work. I couldn’t write this article without his awesome collection of how to write good ARC code.↩
-
Thanks to Tinghui’s comment that
NSTimer
should not be invalidated in dealloc.NSTimer
retains its target, so one should use weak references if the timer is a member of target’s property, else just leave it is fine.↩