Vincent Gable’s Blog

May 26, 2010

drain an NSAutoReleasePool Don’t release it

To clean up an NSAutoreleasePool, do [pool drain]; not [pool release];

In a garbage-collected environment, sending any object a release message is hardcoded by the runtime to do nothing (very quickly). So [pool release] won’t do anything. But [pool drain] will signal the garbage collector to cleanup, and works correctly (just like release) in a non-garbage-collected environment.

Why This Still Matters on an iPhone

The iPhone doesn’t have garbage collection today. That doesn’t mean it never will. RIM and Android both support some kind of garbage collection. I’m too grizzled an Apple developer to not future proof my code, because I’ve been effected by Apple making some major runtime changes (eg. switching between PowerPC, x86, x86_64, and ARM processors). Section 3.3.1 of the iPhone SDK agreement means Apple’s runtime is the only game in town. It pays to be sure your code always plays nicely with it.

Using drain also helps your code will play nice with Mac OS X. That gives you more options to re-use and monazite it. If you decide to go the open-route, it means more people will be able to use your code.

May 25, 2010

Write dealloc FIRST

Filed under: Bug Bite,Cocoa,Objective-C,Programming | , , ,
― Vincent Gable on May 25, 2010

As soon as you give a class a new instance variable (ivar), update the class’s dealloc method (and viewDidUnload, if the ivar is an IBOutlet) to clean up the ivar. Do this before you write the code using the new ivar. Here’s why:

Never Forget

You can’t forget to release an ivar, if the code that reaps it is in place before the code that creates it. Updating dealloc first means less memory leaks.

Even with an impossibly good testing protocol, that catches every memory leak, it’s faster to fix memory leaks before they happen than to track them down after the fact.

You Know More Than They Do

Sometimes there’s an important step that must be done when cleaning up an ivar. Maybe you need to set it’s delegate to nil, or unregister for a notification, or break a retain cycle. You know this when you setup the ivar. But your coworkers don’t know this a priori. When you checkin code that leaks or triggers an analyzer warning, they’ll want to fix it, and since they know less than you do about your code, they’re more likely to miss a crucial step. (Even if you work alone, remember Future You! In N weeks, Future You will have to deal with all the code Present You wrote today … and they’ll be in the same situation as any other co-worker, because they won’t remember everything Present You knows. )

May 24, 2010

Experts are Easier to Fool

Filed under: Quotes,Research,Security | , ,
― Vincent Gable on May 24, 2010

Another counter-intuitive finding is that scam victims often have better than average background knowledge in the area of the scam content. For example, it seems that people with experience of playing legitimate prize draws and lotteries are more likely to fall for a scam in this area than people with less knowledge and experience in this field. This also applies to those with some knowledge of investments. Such knowledge can increase rather than decrease the risk of becoming a victim.

(via Bruce Schneier)

Never Name a Variable “Index”

Filed under: Bug Bite,C++,Cocoa,Objective-C,Programming | ,
― Vincent Gable on May 24, 2010

Never name a variable index, especially in C.

Instead say what it indexes. For example, if it is used to index an array of Foo objects, call it fooArrayIndex, or currentFooIndex.

If the index variable is just used to enumerate over a collection of objects, (eg. for(int i = 0; i < arraySize; i++){…} ) then iterate smarter, using a simpler construct that doesn’t require declaring auxiliary variables. (Eg., in Objective-C use Fast Enumeration). It’s not always possible to do this, but it’s always a good idea to try.1

Why index is Especially Bad in C

The standard strings.h header declares a function named index, that finds the first occurrence of a charicter in a C-string. In practical terms every C program will have the index function declared everywhere.

But when a variable is declared with the name index it shadows the function — meaning the local variable named index takes over the name index, so the function can’t be called anymore:

char * world = index("Hello, World", 'W');
NSLog(@"'%s'", world);

Prints “‘World'”, but

int index = 0;
char * world = index("Hello, World", 'W');
NSLog(@"'%s'", world);

Won’t compile, because an int isn’t a function.

Obviously this is a problem for code that uses the index() function — but honestly modern code probably uses a safer, unicode-aware string parsing function instead. What’s given me the most trouble is that shadowing index makes the compiler give lots of bogus warnings, if you have the useful GCC_WARN_SHADOW warning turned on.

There are other good reasons as, specific to Objective-C, which Peter Hosey covers.

1If you really can’t think of a better name than “index”, I prefer the more terse i. It sucks, but at least it’s shorter. Brevity is a virtue.

May 19, 2010

N.A.R.C.

Filed under: Cocoa,iPhone,MacOSX,Objective-C,Programming,Tips | , , ,
― Vincent Gable on May 19, 2010

How to remember Cocoa memory management:

Think NARC: “New Alloc Retain Copy”. If you are not doing any of those things, you don’t need to release.

–Andiih on Stack Overflow

Personally, I like to immediately autorelease anything I NARC-ed, on the same line. For example:

Foo* pityTheFoo = [[[Foo alloc] init] autorelease];

Admittedly, this makes for some ugly, bracey, lines. But I think it’s worth it, because you never having to worry about calling release if you also…

Use a @property (or Setter) Instead of retain

In other words I would write an init method that looked like:

- (id) init
{
	self = [super init];
	if (self) {
		_ivar = [[Foo alloc] init];
	}
	return self;
}

as:

- (id) init
{
	self = [super init];
	if (self) {
		self._ivar = [[[Foo alloc] init] autorelease];
	}
	return self;
}

(Or [self setIvar:[[[Foo alloc] init] autorelease]]; if you are one of those folks who hate the dot-syntax.)

It’s debatable if using acessors in init and dealloc is a good idea. I even left a comment on that post arguing against it. But since then I’ve done a lot of reflection, and in my experience using a @property instead of an explicit release/= nil solves more problems then it causes. So I think it’s the best practice.

Even if you disagree with me on that point, if the only places you explicitly NARC objects are init, dealloc, and setX: methods then I think you’re doing the right thing.

Cycles!

The last piece of the memory-management puzzle are retain cycles. By far the best advice I’ve seen on them is Mike Ash’s article. Read it.

May 17, 2010

Don’t Check For nil in Your dealloc Methods

Filed under: Cocoa,Programming | , ,
― Vincent Gable on May 17, 2010

There’s no need to check if a variable is nil before release-ing it, because calling a method on a NULL variable is a no-op in Objective-C. And the runtime already has a super-fast check for this case.  So adding an extra if test into your code will probably slow things down.

Doing a pointless ” ==?nil”  test is bad for two reasons.

Firstly, it’s more code for no good reason. Even if it’s just one more line, It’s one more line to debug and test. It’s one more place where something could go wrong.

Secondly, it’s not idiomatic Cocoa-code, so it signals that something strange is going on. That’s a problem for whoever is reading the code, because they have to stop and look around more carefully to figure out why the pointless tests are happening.

In summary, do NOT do this:

– (void)dealloc;

{

if(baseImage) {

[baseImage release];

baseImage = nil;

}

[super dealloc];

}?

Do this:

– (void)dealloc;

{

[baseImage release];

baseImage = nil;

[super dealloc];

}

Powered by WordPress