The "rule" basically says that you have to release the object if
(a) you were the one to call "alloc"
(b) it was created using a method named "create"
Otherwise, you should not, unless you explicitly called "retain".
What's happening is that the
imageWithContentsOfFile: routine builds the image for you, but (since it doesn't have "create" in its name) it also calls "autorelease" on the image for you. This will cause the autorelease pool to call "release" on the returned object when this particular event is over. If you call "release" manually, then the later "release" from the autorelease pool is one too many.
Thus, an object built this way has an "effective" retain count of zero. (If you ask the object for its retain count, it will report "1", but you have to factor in the pending "release" call from the autorelease pool.) Your assignment to [self setImage:image] presumably adds a "retain", so at the end of the event processing, the autorelease pool's "release" doesn't deallocate the object. With your extra "release", however, you've "undone" the retain in your "setImage" method, and thus the "release" in the autorelease pool deallocates the image. "self" is left with a pointer to a dead object.
I hope that's not too twisty to follow.
A slightly more detailed description can be found here:
Very simple rules for memory management in Cocoa