- Testing Equality
- Custom Subclassing
- Reducing Message-Sending
- Copying and Mutability
- Avoid Autoreleasing
- Use the Compiler
- Don't Bother
Copying and Mutability
All Foundation classes do one very simple thing to improve efficiency, and people often fail to consider this fact in their own code: When you send a -copy message to an immutable object, it returns self.
Most imperative languages encourage the idea of defensive copying. If you're not sure whether you want a reference to an object or a copy of it, you should take a copy. This scheme prevents other parts of the program from modifying things that you don't want them to change.
In various bits of Cocoa, you'll see copy methods implemented like this:
- (id)copyWithZone: (NSZone*)aZone { return [self retain]; }
If you send a -copy or -copyWithZone: message to the object, you won't actually get a copy; instead, you'll get a new owned reference. From your perspective, there's no difference, because a copy of an immutable object is semantically equivalent to an identical new object.
Remembering to do this is very important if, for example, you create a custom object type to use as keys in a dictionary. NSDictionary copies objects that are used as keys, so you end up with a lot of redundant copies if your immutable objects are performing real copies.
Another important thing to remember is to copy early. If you send a -copy message to a mutable object, you'll get an immutable copy. If you then send a -copy message to that object, you'll just increase its reference count.
If you keep sending -copy messages to a mutable object, however, you'll keep getting new copies. This approach is a lot more expensive, in terms of both CPU time and memory. Instead, you can make the immutable copy early and keep using it, which is a lot cheaper.
You can find places where you're copying redundantly by looking for -copyWithZone: messages being sent to mutable objects.