ARC and CFType release callback

  • I have a CFType (specifically a CGPattern) that uses a release
    callback to free resources, and the void* pointer passed to the
    callback is the object to be released.

    What's the correct way to release this void* pointer (that's really an
    NSObject subclass) under ARC? Casting it using __bridge_transfer
    doesn't seem right since the resulting expression is unused, and the
    compiler of course warns of this fact.

    Thanks,

    David
  • On Jun 19, 2012, at 8:28 PM, Dave Keck <davekeck...> wrote:
    > I have a CFType (specifically a CGPattern) that uses a release
    > callback to free resources, and the void* pointer passed to the
    > callback is the object to be released.
    >
    > What's the correct way to release this void* pointer (that's really an
    > NSObject subclass) under ARC? Casting it using __bridge_transfer
    > doesn't seem right since the resulting expression is unused, and the
    > compiler of course warns of this fact.

    The right way to handle void* context parameters in ARC is usually one of these:
    For one-shot contexts:
        Set the void* context with CFBridgingRetain(object).
        Retrieve your object with (ObjectType *)CFBridgingRelease(context).

    For persistent contexts:
        Set the void* context with CFBridgingRetain(object).
        Retrieve your object with (__bridge ObjectType *)context.
        Clean up the void* context with CFRelease(context) or (ObjectType *)CFBridgingRelease(context)

    In C++ you'll need extra casts between void* and CFTypeRef.

    If you're talking about the void* info parameter to CGPatternCreate, use the "persistent context" code.

    --
    Greg Parker    <gparker...>    Runtime Wrangler
  • > ¬† ¬†Clean up the void* context with CFRelease(context) or (ObjectType *)CFBridgingRelease(context)

    I see -- I was under the impression that CFBridgingRetain/Release was
    meant for converting to/from CFTypes rather than arbitrary pointers,
    but it works as expected.

    Thanks!

    David
  • On Jun 19, 2012, at 8:58 PM, Dave Keck <davekeck...> wrote:
    > Greg Parker wrote:
    >> Clean up the void* context with CFRelease(context) or (ObjectType *)CFBridgingRelease(context)
    >
    > I see -- I was under the impression that CFBridgingRetain/Release was
    > meant for converting to/from CFTypes rather than arbitrary pointers,
    > but it works as expected.

    Once you have a CFTypeRef via CFBridgingRetain(), ARC doesn't care what you do with it. Convert it to and from uintptr_t, pass it through a void*, send it around via IPC, whatever.

    --
    Greg Parker    <gparker...>    Runtime Wrangler
  • > Once you have a CFTypeRef via CFBridgingRetain(), ARC doesn't care what you do with it. Convert it to and from uintptr_t, pass it through a void*, send it around via IPC, whatever.

    That makes sense. I'm also looking for a pattern similar to this RR
    code, so that I can leave out explicit CFReleases:

        CGPatternRef pattern = [(id)CGPatternCreate(...) autorelease];
        CGColorRef color = [(id)CGColorCreateWithPattern(...) autorelease];

    Is this pattern possible in ARC? I know I could use something like this:

        id pattern = CFBridgingRelease(CGPatternCreate(...));
        id color = CFBridgingRelease(CGColorCreateWithPattern(...));

    But losing the variable type information isn't worth using ARC. I
    figured I could make a special function:

        static void *MyCFAutorelease(CFTypeRef object)
        {
            return (__bridge void *)CFBridgingRelease(object);
        }

    and use code that looks like:

        CGPatternRef pattern = MyCFAutorelease(CGPatternCreate(...));
        CGColorRef color = MyCFAutorelease(CGColorCreateWithPattern(...));

    But this code isn't safe under ARC is it? I would think that since
    they're CFTypes, they're invisible to ARC and can be deallocated
    early.

    Thanks!

    David
  • On Jun 19, 2012, at 10:19 PM, Dave Keck wrote:

    >> Once you have a CFTypeRef via CFBridgingRetain(), ARC doesn't care what you do with it. Convert it to and from uintptr_t, pass it through a void*, send it around via IPC, whatever.
    >
    > That makes sense. I'm also looking for a pattern similar to this RR
    > code, so that I can leave out explicit CFReleases:
    >
    > CGPatternRef pattern = [(id)CGPatternCreate(...) autorelease];
    > CGColorRef color = [(id)CGColorCreateWithPattern(...) autorelease];
    >
    > Is this pattern possible in ARC? I know I could use something like this:
    >
    > id pattern = CFBridgingRelease(CGPatternCreate(...));
    > id color = CFBridgingRelease(CGColorCreateWithPattern(...));
    >
    > But losing the variable type information isn't worth using ARC. I
    > figured I could make a special function:
    >
    > static void *MyCFAutorelease(CFTypeRef object)
    > {
    > return (__bridge void *)CFBridgingRelease(object);
    > }
    >
    > and use code that looks like:
    >
    > CGPatternRef pattern = MyCFAutorelease(CGPatternCreate(...));
    > CGColorRef color = MyCFAutorelease(CGColorCreateWithPattern(...));
    >
    > But this code isn't safe under ARC is it? I would think that since
    > they're CFTypes, they're invisible to ARC and can be deallocated
    > early.

    Correct, that's unsafe. ARC won't retain it because there aren't any object-typed variables pointing to it, and CF stopped retaining it when you said CFBridgingRelease().

    One solution is to write MyCFAutorelease() in a non-ARC file. Then you can call autorelease on your CF objects and ARC will be blissfully unaware.

    #if !__has_feature(objc_arc)
    #  error this file must be compiled with ARC off
    #endif
    CFTypeRef MyCFAutorelease(CFTypeRef obj) {
        return (CFTypeRef)[(id)obj autorelease];
    }

    There might be attributes you can add here to pacify the static analyzer's retain count checking.

    --
    Greg Parker    <gparker...>    Runtime Wrangler
previous month june 2012 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  
Go to today