ARC + return of autoreleased CFType

  • Hi all-

    I've got a category on NSColor to return a CGColor value.  Source looks like this:

    - (CGColorRef)CGColor
    {
        NSColor *colorRGB = [self colorUsingColorSpaceName:NSCalibratedRGBColorSpace];
        CGFloat components[4];
        [colorRGB getRed:&components[0] green:&components[1] blue:&components[2] alpha:&components[3]];
        CGColorSpaceRef theColorSpace = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB);
        CGColorRef theColor = CGColorCreate(theColorSpace, components);
        CGColorSpaceRelease(theColorSpace);
        return theColor;
    }

    My issue is with the final line: the CGColor has a retain count of 1, as it was made with a "Create" function.  Following Cocoa convention, I'd want to cast the return value and autorelease it, but the autorelease call is not allowed under ARC.  Xcode is doing its best to help me figure out how to return the value, but the only thing I can get it to not squeak about is this:

    return (__bridge_retained CGColorRef)(__bridge_transfer id)theColor;

    which does not seem reasonable to me.  Can anyone suggest the proper syntax to return an "autoreleased" CGColorRef from this function?

    Thanks!

    John

    John Pannell
    Following Cocoa convention you'd want to cast it to what and autorelease it? CGColorRef isn't toll-free bridged with anything. If you have been casting it to id and autoreleasing it you might have gotten away with that before but I don't think it's documented anywhere you can do that with CFTypes in general.

    You could change the semantics of the method to return a CFRetain()ed object and make it the responsibility of the caller to release it (and change the name of the method too to make it clear) or you can create a UIColor with your CGColorRef, then CFRelease() it and return the UIColor.

    Mixing autorelease and CFTypes does't seem like a great idea, but I'm prepared for someone to point out a whole piece of documentation I've never seen, that often seems to happen!

    On Oct 19, 2011, at 9:04 PM, John Pannell wrote:

    > Hi all-
    >
    > I've got a category on NSColor to return a CGColor value.  Source looks like this:
    >
    > - (CGColorRef)CGColor
    > {
    > NSColor *colorRGB = [self colorUsingColorSpaceName:NSCalibratedRGBColorSpace];
    > CGFloat components[4];
    > [colorRGB getRed:&components[0] green:&components[1] blue:&components[2] alpha:&components[3]];
    > CGColorSpaceRef theColorSpace = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB);
    > CGColorRef theColor = CGColorCreate(theColorSpace, components);
    > CGColorSpaceRelease(theColorSpace);
    > return theColor;
    > }
    >
    > My issue is with the final line: the CGColor has a retain count of 1, as it was made with a "Create" function.  Following Cocoa convention, I'd want to cast the return value and autorelease it, but the autorelease call is not allowed under ARC.  Xcode is doing its best to help me figure out how to return the value, but the only thing I can get it to not squeak about is this:
    >
    > return (__bridge_retained CGColorRef)(__bridge_transfer id)theColor;
    >
    > which does not seem reasonable to me.  Can anyone suggest the proper syntax to return an "autoreleased" CGColorRef from this function?
    >
    > Thanks!
    >
    > John
    >
    >
    > John Pannell
    >
    On Oct 19, 2011, at 8:04 AM, John Pannell wrote:

    > I've got a category on NSColor to return a CGColor value.  Source looks like this:
    >
    > - (CGColorRef)CGColor
    > {
    > NSColor *colorRGB = [self colorUsingColorSpaceName:NSCalibratedRGBColorSpace];
    > CGFloat components[4];
    > [colorRGB getRed:&components[0] green:&components[1] blue:&components[2] alpha:&components[3]];
    > CGColorSpaceRef theColorSpace = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB);
    > CGColorRef theColor = CGColorCreate(theColorSpace, components);
    > CGColorSpaceRelease(theColorSpace);
    > return theColor;
    > }
    >
    > My issue is with the final line: the CGColor has a retain count of 1, as it was made with a "Create" function.  Following Cocoa convention, I'd want to cast the return value and autorelease it, but the autorelease call is not allowed under ARC.  Xcode is doing its best to help me figure out how to return the value, but the only thing I can get it to not squeak about is this:
    >
    > return (__bridge_retained CGColorRef)(__bridge_transfer id)theColor;
    >
    > which does not seem reasonable to me.  Can anyone suggest the proper syntax to return an "autoreleased" CGColorRef from this function?

    Here's one possibility that I'm not sure will work:

    * Create a utility class to hold a CFTypeRef.  It will CFRetain() it during its init method and CFRelease() it in its -dealloc.

    * Instantiate an instance of that class with theColor.

    * Store the address of that instance to an __autoreleasing-qualified variable.

    * CGColorRelease(theColor), leaving the instance of the utility class as the only owner.

    * Return theColor directly with no other attempt to manage its lifetime.

    I _think_ that ARC will autorelease the utility object due to it being referenced by the __autoreleasing-qualified pointer, rather than releasing it.  And since that object survives for the lifetime of the innermost autorelease pool and owns theColor, theColor survives that long, too.

    The use of the utility class and the extra object is cumbersome, but that may be the best that you can do.  Also, it resolves the hinky-ness of using -autorelease on a non-toll-free-bridged CFType (although I believe that is safe).  Also, the utility class is general purpose and can be used in other similar circumstances.

    Regards,
    Ken
  • On Oct 19, 2011, at 6:24 AM, Roland King <rols...> wrote:

    > Following Cocoa convention you'd want to cast it to what and autorelease it? CGColorRef isn't toll-free bridged with anything. If you have been casting it to id and autoreleasing it you might have gotten away with that before but I don't think it's documented anywhere you can do that with CFTypes in general.

    All Core Foundation objects are at least bridged to NSObject precisely so you can call -retain/-release/-autorelease on  them.

    --Kyle Sluder
  • > Following Cocoa convention you'd want to cast it to what and autorelease it? CGColorRef isn't toll-free bridged with anything. If you have been casting it to id and autoreleasing it you might have gotten away with that before but I don't think it's documented anywhere you can do that with CFTypes in general.

    You can.  It may not be in the docs, but all CF types are also NSObjects (or a subclass thereof).

    > You could change the semantics of the method to return a CFRetain()ed object and make it the responsibility of the caller to release it (and change the name of the method too to make it clear) or you can create a UIColor with your CGColorRef, then CFRelease() it and return the UIColor.
    >
    > Mixing autorelease and CFTypes does't seem like a great idea, but I'm prepared for someone to point out a whole piece of documentation I've never seen, that often seems to happen!

    No, mixing them is indeed a bad idea.  CF doesn't have auto release pools, so anything dealing with CF types is free to not think about them, and in practice often does.  I would go with explicitly returning the CGColorRef retained.
  • Check the nice clear tutorial at http://www.mikeash.com/pyblog/friday-qa-2011-09-30-automatic-reference-coun
    ting.html

    It spells out how to handle CF types in ARC.

    On Oct 19, 2011, at 9:52 AM, Wade Tregaskis wrote:

    >> Following Cocoa convention you'd want to cast it to what and autorelease it? CGColorRef isn't toll-free bridged with anything. If you have been casting it to id and autoreleasing it you might have gotten away with that before but I don't think it's documented anywhere you can do that with CFTypes in general.
    >
    > You can.  It may not be in the docs, but all CF types are also NSObjects (or a subclass thereof).
    >
    >> You could change the semantics of the method to return a CFRetain()ed object and make it the responsibility of the caller to release it (and change the name of the method too to make it clear) or you can create a UIColor with your CGColorRef, then CFRelease() it and return the UIColor.
    >>
    >> Mixing autorelease and CFTypes does't seem like a great idea, but I'm prepared for someone to point out a whole piece of documentation I've never seen, that often seems to happen!
    >
    > No, mixing them is indeed a bad idea.  CF doesn't have auto release pools, so anything dealing with CF types is free to not think about them, and in practice often does.  I would go with explicitly returning the CGColorRef retained.
    > _______________________________________________
  • Many thanks to all who responded.  Here's a few resolutions for the archives:

    1.  CFType: cast to id and autorelease.  Verdict: it is OK (under manual memory management).

    http://www.cocoabuilder.com/archive/cocoa/215004-autorelease-cgimageref.htm
    l

    http://developer.apple.com/library/mac/#documentation/CoreFoundation/Concep
    tual/CFDesignConcepts/Articles/tollFreeBridgedTypes.html


    Sending an autorelease to an object or opaque type puts the pointer into a collection that will later receive a release call.  CFType can be released.  (This has worked for me in practice for quite some time, but I'm looking to move to ARC for a new project).

    2.  Returning an autoreleased opaque type under ARC.  Verdict: Might not even make sense.

    Mike Ash's excellent explanations did help clarify things, but in the end, I'm not sure that my original request is even sensible.  I was looking to hand over an opaque type that was in some collection scheduled to get released later.  I don't think any of the casting annotations amount to this.  Mike's only example of bridging in this direction (toward a CFType) was the __bridge_retained to transfer ownership from the system into our hands, which is where I was in the first place returning the CGColor.

    3.  What to do?  Keep it simple: I'll modify the method name to reflect the need to memory manage the return value - CGImageCopy.  Here is the final method:

    - (CGColorRef)CGColorCopy
    {
      NSColor *colorRGB = [self colorUsingColorSpaceName:NSCalibratedRGBColorSpace];
      CGFloat components[4];
      [colorRGB getRed:&components[0] green:&components[1] blue:&components[2] alpha:&components[3]];
      CGColorSpaceRef theColorSpace = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB);
      CGColorRef theColor = CGColorCreate(theColorSpace, components);
      CGColorSpaceRelease(theColorSpace);
      return theColor;
    }

    Thanks for everyone's input!

    John

    On Oct 19, 2011, at 10:09 AM, John Joyce wrote:

    > Check the nice clear tutorial at http://www.mikeash.com/pyblog/friday-qa-2011-09-30-automatic-reference-coun
    ting.html

    > It spells out how to handle CF types in ARC.
    >
    > On Oct 19, 2011, at 9:52 AM, Wade Tregaskis wrote:
    >
    >>> Following Cocoa convention you'd want to cast it to what and autorelease it? CGColorRef isn't toll-free bridged with anything. If you have been casting it to id and autoreleasing it you might have gotten away with that before but I don't think it's documented anywhere you can do that with CFTypes in general.
    >>
    >> You can.  It may not be in the docs, but all CF types are also NSObjects (or a subclass thereof).
    >>
    >>> You could change the semantics of the method to return a CFRetain()ed object and make it the responsibility of the caller to release it (and change the name of the method too to make it clear) or you can create a UIColor with your CGColorRef, then CFRelease() it and return the UIColor.
    >>>
    >>> Mixing autorelease and CFTypes does't seem like a great idea, but I'm prepared for someone to point out a whole piece of documentation I've never seen, that often seems to happen!
    >>
    >> No, mixing them is indeed a bad idea.  CF doesn't have auto release pools, so anything dealing with CF types is free to not think about them, and in practice often does.  I would go with explicitly returning the CGColorRef retained.
    >> _______________________________________________
    >
  • On Wed, 19 Oct 2011 11:47:22 -0600, John Pannell <john...> said:

    > - (CGColorRef)CGColorCopy

    The CG prefix is not yours to use at the start of a method name. Start with your own prefix.

    Also, follow the convention that if you're handing back a newly created retained object, the word Create appears early in the title. You know there's a rule that Create means a retained ref is returned, so use that rule in your own name, so that when you come back to this code in a year you'll know what's happening.

    Also, be descriptive as to what this method does. "Copy" doesn't really cut it. So, maybe call this something like MyCGColorCreateWithCalibratedSpace (or something - I'm not entirely clear on the purpose of the method).

    m.

    --
    matt neuburg, phd = <matt...>, <http://www.apeth.net/matt/>
    A fool + a tool + an autorelease pool = cool!
    Programming iOS 4!
    On Oct 20, 2011, at 10:11 AM, Matt Neuburg wrote:
    > You know there's a rule that Create means a retained ref is returned

    There is no such rule in the Cocoa memory management conventions.

    http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/Memo
    ryMgmt/Articles/mmRules.html


    There is a "Create" rule in the convention for CoreFoundation functions, but that convention does not apply to Objective-C methods.

    --
    Greg Parker    <gparker...>    Runtime Wrangler
  • On Oct 20, 2011, at 1:20 PM, Greg Parker wrote:

    > On Oct 20, 2011, at 10:11 AM, Matt Neuburg wrote:
    >> You know there's a rule that Create means a retained ref is returned
    >
    > There is no such rule in the Cocoa memory management conventions.
    >
    > http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/Memo
    ryMgmt/Articles/mmRules.html

    >
    > There is a "Create" rule in the convention for CoreFoundation functions, but that convention does not apply to Objective-C methods.

    Sure, but still, he's returning a retained CGColorRef. And CGColor participates in this convention (CGColorRelease, CGColorRetain, CGColorCreate etc.). I'm not saying he has to do it; I'm merely suggesting that the magic word "Create" will help him remember what he's trying to remember, namely that he's returning a retained CGColorRef and the caller will need to call CGColorRelease on it later. m.
  • On Oct 20, 2011, at 3:43 PM, Matt Neuburg wrote:

    >
    > On Oct 20, 2011, at 1:20 PM, Greg Parker wrote:
    >
    >> On Oct 20, 2011, at 10:11 AM, Matt Neuburg wrote:
    >>> You know there's a rule that Create means a retained ref is returned
    >>
    >> There is no such rule in the Cocoa memory management conventions.
    >>
    >> http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/Memo
    ryMgmt/Articles/mmRules.html

    >>
    >> There is a "Create" rule in the convention for CoreFoundation functions, but that convention does not apply to Objective-C methods.
    >
    > Sure, but still, he's returning a retained CGColorRef. And CGColor participates in this convention (CGColorRelease, CGColorRetain, CGColorCreate etc.). I'm not saying he has to do it; I'm merely suggesting that the magic word "Create" will help him remember what he's trying to remember, namely that he's returning a retained CGColorRef and the caller will need to call CGColorRelease on it later. m.
  • On Oct 20, 2011, at 4:43 PM, Matt Neuburg wrote:

    > Sure, but still, he's returning a retained CGColorRef. And CGColor participates in this convention (CGColorRelease, CGColorRetain, CGColorCreate etc.). I'm not saying he has to do it; I'm merely suggesting that the magic word "Create" will help him remember what he's trying to remember, namely that he's returning a retained CGColorRef and the caller will need to call CGColorRelease on it later.

    You're absolutely right, Matt. But it's actually more fundamental than that, now that Xcode 4 has the Analyze command. I don't believe this is documented, but I found out by trial and error that the Core Foundation "create rule" should be followed in Cocoa methods that return Core Foundation CFTypeRef objects, if you want to get optimum results from Analyze.

    Specifically, if your Cocoa method returns a CFTypeRef object retained, and you don't put "Copy" or "Create" in the method name, Analyze reports a "potential" memory leak. Go back and insert "Copy" or "Create" into the method name, and Analyze no longer reports a potential memory leak. To me, it makes all the sense in the world to apply the "create rule" to Cocoa methods that return Core Foundation CFTypeRef objects.

    I found this discovery extraordinarily helpful in using Analyze to kill memory issues in a couple of frameworks I distribute. The frameworks make heavy use of CFTypeRef objects. I would love to hear from anybody at Apple who can confirm that this is the way Analyze is meant to work.

    --

    Bill Cheeseman - <bill...>
  • Le 20 oct. 2011 à 23:38, Bill Cheeseman a écrit :

    >
    > On Oct 20, 2011, at 4:43 PM, Matt Neuburg wrote:
    >
    >> Sure, but still, he's returning a retained CGColorRef. And CGColor participates in this convention (CGColorRelease, CGColorRetain, CGColorCreate etc.). I'm not saying he has to do it; I'm merely suggesting that the magic word "Create" will help him remember what he's trying to remember, namely that he's returning a retained CGColorRef and the caller will need to call CGColorRelease on it later.
    >
    >
    > You're absolutely right, Matt. But it's actually more fundamental than that, now that Xcode 4 has the Analyze command. I don't believe this is documented, but I found out by trial and error that the Core Foundation "create rule" should be followed in Cocoa methods that return Core Foundation CFTypeRef objects, if you want to get optimum results from Analyze.
    >
    > Specifically, if your Cocoa method returns a CFTypeRef object retained, and you don't put "Copy" or "Create" in the method name, Analyze reports a "potential" memory leak. Go back and insert "Copy" or "Create" into the method name, and Analyze no longer reports a potential memory leak. To me, it makes all the sense in the world to apply the "create rule" to Cocoa methods that return Core Foundation CFTypeRef objects.
    >
    > I found this discovery extraordinarily helpful in using Analyze to kill memory issues in a couple of frameworks I distribute. The frameworks make heavy use of CFTypeRef objects. I would love to hear from anybody at Apple who can confirm that this is the way Analyze is meant to work.
    >

    If you want to avoid ambiguity, just add a CF_RETURNS_RETAINED annotation attribute to your method.

    -- Jean-Daniel
  • On Oct 20, 2011, at 15:38 , Jean-Daniel Dupas wrote:

    > Le 20 oct. 2011 à 23:38, Bill Cheeseman a écrit :
    >
    >> I found this discovery extraordinarily helpful in using Analyze to kill memory issues in a couple of frameworks I distribute. The frameworks make heavy use of CFTypeRef objects. I would love to hear from anybody at Apple who can confirm that this is the way Analyze is meant to work.
    >>
    >
    > If you want to avoid ambiguity, just add a CF_RETURNS_RETAINED annotation attribute to your method.

    And I'll just throw in this reference:

    http://clang-analyzer.llvm.org/annotations.html

    which I found to be a good overview of what the analyzer is trying to do, though it doesn't address Bill's question directly.
previous month october 2011 next month
MTWTFSS
          1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
31            
Go to today