UPDATE: This issue has been fixed as of Xcode 4.6!
This technique now works as intended again. However, make sure to read the notes at the top of Rob Napier's excellent answer before you use it in your code.
ORIGINAL POST
(ARC, Xcode 4.3.1, iOS 5.1)
I have a strong property of a CF type (CGImage) that I want to be automatically managed by ARC using __attribute__((NSObject))
(as in having retain & release in the synthesized setter, and it being nil'ed in dealloc), but it doesn't work: the object is not retained when I assign the property.
A minimal example to reproduce:
@interface TestClass : NSObject
@property (nonatomic, strong) __attribute__((NSObject)) CFStringRef str;
@end
// ...In some function
CFStringRef str = (__bridge CFStringRef)[NSString stringWithFormat:@"%g", 2.5];
NSLog(@"%ld", CFGetRetainCount(str));
TestClass *obj = [[TestClass alloc] init];
obj.str = str;
NSLog(@"%ld", CFGetRetainCount(str));
Which prints '1' twice.
Now the strange thing is that (although I'm not sure of this) I think it worked properly before I updated to iOS 5.1 & Xcode 4.3.1 (from iOS 5 & Xcode 4.2), and with it switched from gdb to lldb. Can someone who hasn't upgraded (or knows how to change back the compiler) perhaps confirm?
EDIT2 (Mar 2013) FYI for those interested in this technique, ARC documentation for clang includes the following note:
EDIT The below is interesting, but probably irrelevant. This is a bug and you should open a radar. As noted by @lnafziger, this is legal and is supposed to be honored. The bug is that it is not honored when you include
nonatomic
. If you removenonatomic
, then it works. Nothing in thenonatomic
definition suggests that this is by design.This is kind of clever, but I think I see why it isn't working. You can confirm, btw, that it isn't working by generating the assembler and noting that
setStr:
does not callobjc_storeStrong()
. It does a simple assign.The problem is that your property definition does not conform to the definition of a retainable object pointer (emphasis added):
Did you create a typedef as specified? No you did not. OK, so how would we do this?
This will print "1" and then "2" as I assume you expect. Scares me for unspecified reasons, but looking at the assembler output, everything seems fine and I can't think of any specific problem or violation here.
You could be justified in opening a radar for this. The fact that a typedef is not treated the same as a specified type is surprising at least, even if documented.
EDIT: Noting @lnafziger's comment from the ObjC Programming Language, there is definitely either an error in the ARC spec/implementation or an error in the linked document, so one of them should be fixed.