1

I have custom UIView drawing in drawRect.

I don't know the C APIs that well so I'm not sure what memory rules they require. The Objective-C rules are pretty simple and state that you release anything you own via init retain or copy but the C function CGGradientCreateWithColorComponents is not Objective-C and the Product > Analyze reports that it is a potential leak.

Is it necessary to release the results of this function, and if so, how? And in general, when it comes to these APIs, is there any easy way to know if a function is allocating memory that you need to manually release?

UPDATE: Here is the code, thanks to the information in the answers so far. I'm getting incorrect decrement error now:

CGGradientRef theGradient=[self makeGradient:YES];
//do something with theGradient in my drawing
CGGradientRelease(theGradient); // this line Analyze says incorrect decrement of object not owned by caller

And in makeGradient I have:

 - (CGGradientRef)makeGradient:(BOOL)red{
     CGGradientRef gradient;
     //create my gradient
     return gradient;
 }
David Rönnqvist
  • 56,267
  • 18
  • 167
  • 205
johnbakers
  • 24,158
  • 24
  • 130
  • 258
  • 1
    Too lazy to type an answer, but here: https://developer.apple.com/library/mac/documentation/CoreFOundation/Conceptual/CFMemoryMgmt/Concepts/Ownership.html#//apple_ref/doc/uid/20001148-103029 (Also can't find anything saying specifically that this applies to CG) — and also see http://stackoverflow.com/questions/7800174/does-arc-work-with-core-graphics-objects – jtbandes Aug 08 '12 at 06:06
  • @jtbandes The *[CGGradient Reference](http://developer.apple.com/library/ios/#DOCUMENTATION/GraphicsImaging/Reference/CGGradient/Reference/reference.html)* tells you that a `CGGradient` is derived from `CFType`. – rob mayoff Aug 08 '12 at 06:11

2 Answers2

6

The general rule is that if you call function whose name contains “Create” or “Copy”, you must release the object that it returns. This is called the “Create rule”.

You created the gradient using a function that has “Create” embedded in the name. That means you're responsible for releasing the gradient. You can use CGGradientRelease or CFRelease.

You can read about the Create rule and other memory management conventions in the Memory Management Programming Guide for Core Foundation.

You can also read Quartz 2D Programming Guide: Memory Management: Object Ownership.

UPDATE

Based on your new code samples, I now see that you need to learn about another memory management convention. ;^)

Objective-C methods use a slightly different naming convention than Core Foundation functions. Instead of putting “Create” or “Copy” in the name, the convention for Objective-C methods is that the name must start with “alloc”, “new”, “copy”, or “mutableCopy” if it returns an object that the caller must release. (You can read about Objective-C memory management conventions here.)

Change the name of your method from makeGradient: to newGradient: and the analyzer will stop complaining. I tested it! :^)

rob mayoff
  • 375,296
  • 67
  • 796
  • 848
  • thanks, and if I need to first return the gradient before releasing it, is the chore of the release left to the recipient of the function's return? With Obj-C I would add autorelease to the `return` statement around the object my function returns. – johnbakers Aug 08 '12 at 06:11
  • 1
    If you're going to return it, you should not release it. And you should try to follow the naming convention yourself to make it clear that the caller is responsible for releasing. – rob mayoff Aug 08 '12 at 06:13
  • i've updated my question with the progress and code based on your suggestion. – johnbakers Aug 08 '12 at 06:19
  • @andrewx, you get the new warning because the analyzer knows the Create Rule, and sees that your method name doesn't indicate ownership -- change the method name to include `Create` and you'll be fine, – jscs Aug 08 '12 at 06:20
  • If the method I create myself were named with Create, would the Analyzer be smart enough to know it then, you think? As it is now, is my memory management correct? – johnbakers Aug 08 '12 at 06:21
  • @rob, re: your update, the analyzer will also accept `create` anywhere in the method name as long as the return type is a `CFType`. – jscs Aug 08 '12 at 06:27
  • @W'rkncacnter I tested calling it `createGradient:` first and the analyzer still complained. That's why I said to use `newGradient:`. – rob mayoff Aug 08 '12 at 06:28
  • beautiful. got it working and no errors in Analyzer now. great learning here today! – johnbakers Aug 08 '12 at 06:35
  • @rob: Really?! Huh. I get no complaints if `create` is _anywhere_ in the method name. I'm running 4.3 at the moment -- I suppose the analyzer may have changed (I assume you're on a newer version). – jscs Aug 08 '12 at 06:36
  • 1
    You can also use the NS_RETURNS_RETAINED annotation: http://clang-analyzer.llvm.org/annotations.html#attr_ns_returns_retained to prevent the analyzer from complaining. – Cyrille Aug 08 '12 at 08:19
  • @Cyrille Good point. It's probably better to stick to the naming convention, though, since the method name is visible everywhere that it's used, but the `NS_RETURNS_RETAINED` is only visible where the method is declared. – rob mayoff Aug 08 '12 at 08:26
  • If you needed to put a prefix on the method name for some reason (like to prevent a collision with some inherited method), then `NS_RETURNS_RETAINED` would be appropriate. – rob mayoff Aug 08 '12 at 08:27
1

With CGGradientRelease, simply.

Cyrille
  • 25,014
  • 12
  • 67
  • 90
  • how to use this function if you first need to `return` the gradient? With Obj-C I would add `autorelease` around the objected my function returns. – johnbakers Aug 08 '12 at 06:09
  • There's no auto release pool as CG objects are not NSObjects but plain C pointers. Just remember that your custom function returns a retained gradient and you'll need to release it at some point in your code. – Cyrille Aug 08 '12 at 06:11
  • @andrewx: Unfortunately, with CFTypes, you have to pass ownership all the way up (unless you want to build your own autorelease pool) -- the caller of your function will ultimately be responsible for releasing this object, and your function's name should indicate that (the Create Rule). – jscs Aug 08 '12 at 06:13
  • i've updated my question with the progress and code based on your suggestion. – johnbakers Aug 08 '12 at 06:19