I am wrapping a certain C API in Objective-C. I have a convenience method that takes some CFTypeRef
from the procedural API and returns a wrapping object from the OOP API. This object keeps the passed CFTypeRef
and releases it upon its own deallocation. The convenience method looks like this:
+ (id) wrapFoo: (CFTypeRef) foo;
I have a lot of methods that simply get some CFTypeRef
and return the wrapping object:
- (id) doSomething {
CFTypeRef foo = CFCreateSomeObject();
id wrapper = [WrappingClass wrapFoo:foo];
CFRelease(foo);
return wrapper;
}
This is a bit clumsy, so that I came up with another convenience method:
+ (id) wrapNonRetainedFoo: (CFTypeRef) foo {
id wrapper = [self wrapFoo:foo]; // CFRetains foo
CFRelease(foo);
return wrapper;
}
Now I can rewrite the doSomething
method like this:
- (id) doSomething {
return [WrappingClass wrapNonRetainedFoo:CFCreateSomeObject()]; // XXX
}
I like this. I’m not really proud of the wrapNonRetainedFoo
method, but it’s not a part of the public interface of the package and saves me several lines of boilerplate code in several methods.
The downside is that the static analyzer flags the XXX
line as a potential leak. What can I do better? I tried to toy with the cf_consumed
argument attribute to let the analyzer know that I’m releasing the object later, but it does not seem to work.
1) AFAIK cf_consumed is still not supported in versions of analyzer Apple uses.
2) I've noticed that if you make wrapNonRetainedFoo
instance method warning will mysteriously disappear. But since wrap...
is better to be a class method this is of no use to us.
3) Only solution I can think of is this ugly macro (not for production, just as proof of concept):
#define WRAP_CFTYPE(klass, valExpr) ({ CFTypeRef val = valExpr; id result = [klass wrap:val]; CFRelease(val); result; })
Usage:
WrappingClass *wrapper = WRAP_CFTYPE(WrappingClass, CFArrayCreate(NULL, NULL, 0, NULL))