Borkware Miniblog

September 19, 2010

Stay out of Apple’s Namespace

Filed under: Uncategorized — Mark Dalrymple @ 5:00 pm

I’ve been noticing a disturbing trend lately.

A friend asked me recently, “Would naming your own Objective class prefix with NS be an issue with Apple or that is just not good in general?”.

An industry luminary retweeted an otherwise useful macro:

#define CFAutorelease(cf) ((__typeof(cf))[NSMakeCollectable(cf) autorelease])

And recently I saw a blog post where they make their own CLLocationCoordinate2DMake, and then go through contortions to fix things when Apple introduced their own version in a later SDK.

Don’t do this! Stay out of Apple’s Namespace.

There are two big reasons to do this:

  1. Apple changes things. Often. If you add a function, macro, class, or struct in their namespace, you may break. People who use your code may break. People who cut and paste your tweets may break.
  2. It’s confusing for the person reading your code 3 years from now. Or your new hire. Or someone who uses part of your open source library. Or you include it into a posting on a mailing list or stack overflow. “CFAutorelease, I didn’t know that existed.” “uh, sorry, it really doesn’t.”

In general, you should stay out of the namespaces of any code you’re using, such as making your own GTM-named classes if you’re using the Google Toolbox For Mac. That could break you the next time Google revs that library.

CF, NS, CLLocation, etc. Those aren’t your playground.
That’s Apple’s turf. Which kind of makes me sad, since I’m doing stuff for Cycling Fusion now, and using the obvious prefix would be a disaster.

Pick your own prefix and use that. BWCFAutorelease, BWCLLocationCoordinate2DMake. This shows that yes, this is not part of Apple’s API, but also clearly shows the intent of the symbol. Without you being broken by Apple in the future.

September 10, 2010

QFF: Where’s it live?

Filed under: programming, Questions From Friends — Mark Dalrymple @ 8:52 pm

Friend asked on AIM:

I’m curious about how static variables work. Presumably they aren’t stored in the stack, right? So how come you don’t have to store it as a pointer?

They’re just global variables, but with limited visibility. So their actual storage is off with all the other global variables, but nobody outside of that function can actually see it. like having a spy in their midst.

Where is that? I guess my confusion is that it seemed like the sort of thing you’d have to allocate memory for.

Have an illustration:
memory.png

so the arrows show where stuff lives / ends up. arg and the local vars are on the stack.
The four bytes for the ‘blah‘ pointer is on the stack. The return from malloc is in the heap, and the static local is off hanging out with the globals.

I thought char * blah and static char blah were basically the same thing

char * blah has a short life span. Kind of like a firefly.

static char *blah has a long life span. Kind of like a roach that’ll never leave the kitchen. attacks with Raidâ„¢ notwithstanding.
Definitely a kill -9 situation then.

So with char * blah if you forget to free the memory before the function exits you can’t get to it again, right? Because the pointer to it is gone

if you do char *blah = malloc (23); and then exit the function before free() ing, then yes, it’s gone. It’s occupying space, but there’s no map to find it

So that’s a leak

Yep!

September 6, 2010

Block Retain Cycles

Filed under: amosxp, programming — Mark Dalrymple @ 10:37 pm

So I’ve seen in a couple of places where you can get retain cycles with Objective-C blocks, and then have to do some contortions to get a __block-storage-class self pointer that won’t be auto-retained.

But I couldn’t find a simple example to demonstrate the problem, and I want to verify the problem before it gets cast into dead trees or implanted into student’s minds.

So here is minimal example. First is a typedef for a block pointer, and a simple object that holds on to the block:

// Just a simple block pointer that asks for nothing and gives nothing.
typedef void (^BlockHead)(void);

// The leaky object.
@interface Leakzor : NSObject {
    NSString *string;
    BlockHead blockhead;
}

// Print |string|.
- (void) funk;

@end // Leakzor

This will leak the object and the block due to the retain cycle:

- (id) init {
    if ((self = [super init])) {
        string = @"snork";

        // |string| is the same as self->string, so |self| is retained.
        blockhead = Block_copy(^{
                NSLog (@"string is %@", string);
            });
    }
    return self;
} // init

If you compile blockcycle with -DRETAIN_CYCLE=1 you won’t see the dealloc NSLog. Why?

blockhead has caused self to be retained. self won’t be released until blockhead is cleaned up in -dealloc. But -dealloc won’t get called because self is still retained by the block. This is a classic retain cycle.

So how to fix it? With these hoops:

        // |blockSelf| is __block scope, so won't be auto-retained
        __block Leakzor *blockSelf = self;
        blockhead = Block_copy(^{
                NSLog (@"string is %@", blockSelf->string);
            });

So now I access string by using the self pointer, but in the shape of a __block-storage-class local variable. This doesn’t have the retain behavior that ordinary variable capture has.

Does this mean that I’m going to be peppering every block that refers to self, directly or indirectly, with this stuff? Nope. But it’s something to keep in mind, especially if you’re making a copy of a block and then dealing with its cleanup in -dealloc (vs some kind of good-bye kiss method).

The Shocking Blue Green Theme. Create a free website or blog at WordPress.com.

Follow

Get every new post delivered to your Inbox.