Objective-C Memory Management

Perhaps I’m showing my age, but I’m getting awful tired of language designers trying to improve on C/C++ memory management.

Just for review, here’s how memory management should work:

void foo()
  {
  // x is created on the stack. It is deallocated at the end of
  // the block/function and therefore its lifetime matches its
  // scope with no further effort. 

  int x;

  // pX is a pointer to an int that the programmer creates with
  // new. By using "new", the programmer is taking responsibility
  // for freeing the memory used by pX before it goes out of scope.

  int *pX = new int(0);

  // ... interesting code goes here ...

  // The obligatory delete before we exit the block/function.

  delete pX;

  }

Everything else in C/C++ is a variation on this. You can put pointers and variables in structures and classes/objects but they follow the same rules: If you allocate with new, you must free with delete before you lose track of the memory (i.e. the one and only (or last remaining) pointer goes out of scope).

When we started coding for iOS, we ran into “manual retain/release” which is a variation on the C/C++ technique (or rather, a manual method of the automatic garbage collection used in Mac OS):

@interface bar
  {
  // Like C++, when the pointer is a member (instance) variable, 
  // someone else is responsible for allocating memory for it.

  NSString * memberString;
  NSString * anotherString;
  }

// But if the instance variable is accessible from the outside
// world we can say it's a "property" and some of this is 
// managed for us. 

@property (retain) NSString * memberString;

// Unless we don't specify "retain". Now we're responsible for
// making sure the memory for anotherString is allocated and
// freed.

@property (assign) NSString * anotherString;

@end

@implementation bar

- (void)foo
  {
  // These are the same. They're on the stack and are automatically 
  // released when you exit the method/block.

  int x;

  // This is the equivalent of C/C++ "new", kind of. We can't just
  // do memory allocation without also initializing the object 
  // (handled by new and the constructor in C++, but that's the 
  // subject of a different article). The result is a pointer that
  // we're obligated to release before string goes out of scope.

  NSString * string = [[NSString alloc] init];

  // Another way of doing the same thing, but this time the 
  // resulting pointer is automatically released sometime in
  // the future that we don't care about.

  NSString * arString = [[[NSString alloc] init] autorelease];

  // Yet another way of doing the same thing, but the autorelease
  // is done for us. We can tell because the method name starts
  // with something that looks like the name of the class but
  // without the prefix. Intuitively obvious, right?

  NSString * autoString = [[NSString alloc] stringWithUTF8String:"Automatically released"];

  // Required release

  [string release];
  }

@end

And autorelease isn’t as automatic as you might think. You need to think about whether or not you need to create your own autorelease pool. This is important if you’re going to create a large number of autoreleased variables before returning to the run loop. You may want to manage your own autorelease pool in that case so you can free memory up at more convenient times.

If that’s not ridiculous enough, along comes Automatic Reference Counting (ARC) to “simplify” memory management.

@interface bar
  {
  // Like C++, when the pointer is a member (instance) variable, 
  // someone else is responsible for allocating memory for it.

  NSString * memberString;
  NSString * anotherString;
  }

// Instead of "retain", we create a "strong" reference. Memory
// is freed when this particular instance variable goes out
// of scope (is no longer accessible). 

@property (strong) NSString * memberString;

// We use "weak" instead of "assign" to mean that we understand
// someone else is in control of when this memory gets freed.

@property (weak) NSString * anotherString;

@end

@implementation bar

- (void)foo
  {
  // These are the same. They're on the stack and are automatically 
  // released when you exit the method/block. In reality, they're
  // qualified with __strong by default.

  int x = 10;
  NSString * string = [[NSString alloc] init]; // could add __strong for clarity

  // You can also create weak pointers for some reason:

  NSString * __weak weakString;

  // Unfortunately, that introduces a bug into these lines of code:

  weakString = [[NSString alloc] initWithFormat:@"x = %d", x];
  NSLog(@"weakString is '%@'", weakString);

  // In the code above, weakString is immediately deallocated after
  // it is created because there is no strong reference to it. See
  // how this is getting easier?

  // Not to mention:

  NSString * __autoreleasing arString;
  NSString * __unsafe_unretained uuString;

  // Now we don't have to do this:
  // [string release];
  // And that's really all we saved by introducing "Automatic Reference Counting".
  // At the same time, we created a new way to introduce a bug by failing
  // to have any strong pointers to an object from one line of code to
  // the next.
  }

@end

So we’ve gone from:

new / delete

to

retain / release (or autorelease with no release)

to

strong/__strong/weak/__weak/__autoreleasing/__unsafe_unretained

all in the interest of “simplification” and avoiding having to delete/release the memory we allocate. I frankly don’t see the benefits.

My Computer Bag

Tumi Expandable Leather Laptop BagI’ve been accused of having something of a luggage fetish, though more in the past than recently. Back in my Parsons Technology days I spent a fair amount of time on the road — nothing like my friend Dave, but more than most folks — maybe 3-5 days per month. It only took a couple of trips to figure out that the old suitcases in the closet weren’t up to the task, and what followed over the years was a series of suitcases and carry-ons as I tried to zero in on what worked best for me.

I’ve been traveling with a laptop since there were laptops. One of the first IBM-compatible PCs I used was a Compaq Portable. It weighed 25-30 lbs, but Rockwell had a padded case for it that made it look like a soft-side suitcase, and we literally checked it as luggage when we travelled with it. My first PC was a Compaq Portable II, but after traveling with and repairing Rockwell’s Compaq, I never traveled with it. In 1988 I bought a Toshiba T1200. Some of the early QuickVerse code was written while on the road with that laptop.

Throughout this period of heavy business travel, one constant companion was my Tumi leather laptop bag, which I purchased around 1989 for about $450. It was a crazy price to pay for a laptop bag, but this one had everything I was looking for and 25 years later I still carry it every day.

The front of the bag features a large and a small zippered pocket, each with a small zippered pocket on the front of it. Behind those pockets is a large, open compartment for cables and other bulky items. It has a small organizer sewn to one side that holds pens and business cards and gives you quick access to a calculator (back in the day), PDA (still back in the day), or a phone (there you go).

The second large compartment is divided into sections and opens up like a portfolio file. I find this side ideal not just for papers, notebooks, and other flat items, but also for my laptop. On the back of the bag is a large, flat, zippered pocket. On the back of that pocket, the straps from the handles form open loops that allow you to easily carry a newspaper (a what?) or an umbrella (ah, that’s better).

The bag has a leather handle sewn to each side. After 25 years of regular use, these handles are still firmly attached. There’s also a clip on shoulder strap that I leave permanently attached to the bag.

For short trips, I’ve found I can use the expansion feature to give me room to pack a change of clothes and shaving kit right in the bag. Just unzip the zipper that runs around the center section of the bag, and you gain 2-3 inches of space in the open compartment on the front of the bag.

Tumi still sells a version of this bag for $650, but they’ve removed the little organizer on the inside and replaced the umbrella straps with a feature that allows you to slide the pull-out handle of your wheelie through the pocket on the back so you can carry it with your suitcase. My Travelpro carry-on has a hook that I can use to carry the Tumi bag, so I don’t need this feature.

Even though Laridian started renting office space about two years ago, I still work one or two days per week at home or in a coffee shop. My MacBook lives in my Tumi bag, and my Tumi bag goes with me wherever I go. You can laugh at spending $450 for a computer bag, but if you divide by the number of years it’s lasted, you’re looking at $18/year and falling. That’s a great investment.