5

I'm creating a category on NSDate that that converts a NSDate into a NSString. It uses an NSDateFormatter to do so. I found that allocating then deallocating the formatter each time was causing noticeable delays in my application (this category is used very frequently), so I updated my 'format' method to look like this:

- (NSString *)pretty
{   
    static NSDateFormatter *formatter = nil;

    if (formatter == nil)
    {
        formatter = [[NSDateFormatter alloc] init];
        [formatter setDateStyle:NSDateFormatterLongStyle];
        [formatter setTimeStyle:NSDateFormatterNoStyle];
    }

    return [formatter stringFromDate:self];
}

Is this the correct way to handle a static variable in Cocoa? Is this a leak (no dealloc after alloc)? Does a better way exist of doing something like this? Thanks!

Stussa
  • 3,375
  • 3
  • 24
  • 35
  • Note that you should name your method something with a prefix; i.e. `MyApp_pretty` or something. Prevents collisions. – bbum Jun 01 '11 at 19:36

2 Answers2

9

You are effectively creating a singleton. Unless it isn't going to be used throughout the entire running session of your application, don't worry about the memory use. Even if it is only going to be used intermittently, leaving one date formatter around isn't going to be an issue.

I.e. just like a singleton, don't worry about releasing the object prior to application termination.

If pretty were to be pounded on from multiple threads (and assuming that NSDateFormatter itself is thread safe -- I didn't check the docs and, thus, don't write the code without verifying thread safety), then you'd want to protect the initialization.

static dispatch_once_t onceMark;
static NSDateFormatter *formatter = nil;
dispatch_once(&onceMark, ^{
        formatter = [[NSDateFormatter alloc] init];
        [formatter setDateStyle:NSDateFormatterLongStyle];
        [formatter setTimeStyle:NSDateFormatterNoStyle];
});
bbum
  • 162,346
  • 23
  • 271
  • 359
-1

I believe you should retain the formatter lest it be leaked and you'll get a crash, perhaps spuriously, the next time the formatter is used.

For what it's worth, I do this very thing with NSDateFormatter objects in a category, as I too observed that NSDateFormatter allocation was slowing down my app.

Mark Granoff
  • 16,878
  • 2
  • 59
  • 61
  • 6
    Not necessary, the retain count is already +1 because of the alloc. – Firoze Lafeer Jun 01 '11 at 17:45
  • @Mark doesn't the alloc set a positive retain count automatically? – Stussa Jun 01 '11 at 17:53
  • I thought the retain count would only be incremented if `formatter` was a property and was assigned using dot notation... My experience is that you have to retain it here. Although this could be considered sloppy, an extra retain in this case, isn't so bad: You want the object to stick around for the life of the program anyway. In any case, I am happy to be enlightened. :-) I still get the memory management stuff wrong sometimes! – Mark Granoff Jun 01 '11 at 17:58
  • 2
    NARC; +new, +alloc, -retain and -copy all increase the retain count by one. – bbum Jun 01 '11 at 18:09
  • @bbum: Thanks. The nuance here with static is that it is just that: static, meaning it will not be going out of scope, which means it won't be released. And the extra retain would be, well, extra. So the OP's example is spot on correct! – Mark Granoff Jun 01 '11 at 18:11
  • 1
    In a non-garbage-collected environment, retain counts have nothing to do with scope, so it's not actually a nuance with static. – Matt Wilding Jun 01 '11 at 18:15