Practices

Best Practices

Apple Coding Guidelines

Coding Guidelines

Readability

Write code for people to read, not the compiler.

ARC

Use ARC (Automatic Reference Counting) if at all possible.
ARC is supported in iOS 4.0+ with the single exception that weak reference nilling only available in iOS 5.0+.

Designated initializer

Every class needs a designated initializer and the method should start with “init”. Every other initializer must call the designated initializer.

Indenting

In Xcode use control-i for re-indent

Refactoring

In Xcode use “Edit in Scope” (right-click on a variable, select the down-arrow to the right) to change all instances of a variable at the same time.

Simplest

[NSMutableArray array]

instead of

[[NSMutableArray arrayWithCapacity:value]

Because it is clear and generally just as fast

Comments

Don’t add comments that duplicate the method call naming. If the method call naming needs a comment refactor the method name.

Method names

// Compose URL

NSURL *url = [NSURL URLWithString:urlString];

// Init validator with url

StoreVerifier *verifier = [[StoreVerifier alloc] initWithUrl:url store:storeCopy];

// Begin address validation

serverType = [verifier validateAddressWithAsyncHttp];

Method names should be verbs (action)

// Update UI.

[self validationHasBegun];

beter

[self updateGUIForValidationHasBegun];

Tangelo-Mac-mini:Cocoa2HTML tangelo$

Description

Create class “description” methods.

Constructors

Favor full constructors to multiple setters. The designated initializer should have enough arguments to fully create a usable instance without needing to use setters. If there are “to many” arguments the class is probably trying to do to much and should be broken up into multiple classes.

NSAssert

Use NSAssert(NO, @”message”); for programmer errors.

setters/getters

Name setters/getters from the client perspective

Refactor

Get code working then refactor structure

Collections

If possible instead of providing a collection getter provide an enumerator to a caller.

case

Instead of a case (or if/else/…) that selects code consider subclassing. Using case to select data if fine.

NSDictionary

Do not use dictionaries as substitutes for classes.

Comments

Delete all commented out code (you can always recover it from the source control system).

Boy Scout Principal

When editing any file leave it in better condition that you found it.

Constant Strings

There is no size saving with stringWithString but there may be a slight performance degradation. The @”string” is still a compiled-in constant.

NSString *desc = [NSString stringWithString:@"Text"];

vs

NSString *desc =@”Text”;

NSString* urlString = [NSString stringWithString:@"http://"];

urlString = [urlString stringByAppendingString:address];

vs

urlString = [@"http://" stringByAppendingString:address];

or

urlString = [NSString stringWithFormat:@"http://%@", address];

Retain (or Strong) vs Copy

Copy because the property may be set with a mutable string and copying will reduce the possibility mutating the string.

@property(nonatomic, retain) NSString *address;

    vs

@property(nonatomic, copy) NSString * address;

There is no cost of copying an immutable string.

Brent Simmons says no
Bill Bumgarner says yes, especially for NSString

Public vs Private

Only put methods, properties and ivars that are part of the public interface By Design in the interface file (.h).
Put private methods in a class extension in the implementation file (.m).
Put private @properties in a class extension in the implementation file (.m).
Put private ivars in the @implementation of the implementation file (.m). llvm 4.0 and above

Properties

In Xcode 4 and above it is not necessary to declare ivars for properties
In llvm 4 and above @synthesize is not necessary nor is declaring an ivar and defaults to creating an ivar for the property with an leading underscore.

Source Control Commit

Always compare prior to commit and make the commit comment match the changes.

get…

Use the “get” prefix only for methods returning results via reference in the parameter list and ake the reference var(s) last.

- (NSArray *)contentsOfDirectoryAtPath:(NSString *)path error:(NSError **)error {}

In Objective-C, pass by reference smells like you are doing it wrong with very few exceptions.
Output arguments are counterintuitive, have it change the state of the object it is called on if necessary.

NSError is an exception.

- (void)getCharacters:(unichar *)buffer {}

Dot notation

Do not use dot for behavior.
Use dot to access or set attribute like things, typically attributes declared as properties.

These are OK even though they are not properties because they smell like properties:

k = anArray.count;

for (NSView *v in myView.subviews) { … };

Method Names

Method names should have the last word prior to the argument specify the argument.

Good: – (void)carsWithColor:(UIColor *)color wheels:(NSInteger)wheels;

Bad: – (void)cars:(UIColor *)color wheels:(NSInteger)wheels;

Method names should start with a lower case letter
Class names start with an upper case letter

Simple variants

    [NSMutableArray array];

instead of:

    [NSMutableArray arrayWithCapacity:value];

It is clearer, easier and probably just as fast
Less code means fewer errors and less thought taken away from more important aspects for the code.

NARC

N – new
A – alloc
R – retain
C – copy
Methods with names containing NARC return a retained object.
Methods with names not containing NARC return an autoreleased object.
Core foundation methods named Create… return retained objects and CFRelease() must be called.

Dealloc

Put the dealloc method below the last init method
It is as important as init…

OrNil

If a method parameter can be either a value or nil add OrNil to the name:

+ (UINib *)nibWithData:(NSData *)data bundle:(NSBundle *)bundleOrNil;

NSNotification

Only use when the sender does not know the receiver and/or there are multiple receivers.
Use the Apple recommended naming convention:
[Name of associated class] + [Did | Will] + [UniquePartOfName] + Notification
Examples:

NSApplicationDidBecomeActiveNotification

NSWindowDidMiniaturizeNotification

NSTextViewDidChangeSelectionNotification

NSColorPanelColorDidChangeNotification

Commented-Out Code

When you see commented-out code, delete it! Don’t worry, the source code control system still remembers it.

DRY principle

“Don’t Repeat Yourself”
Duplicated code means duplicate changes when updating code and the likely chance not all instances will be updated.
Every time you see duplication in the code, it represents a missed opportunity for abstraction.

Vertical Separation

Variables and function should be defined close to where they are used.
Private functions should be defined just below their first usage.
Finding a private function should just be a matter of scanning downward from the first usage.

Use Explanatory Variables

Break the calculations up into intermediate values that are held in variables with meaningful names.

Method Names

Method names should say what they do.
If you have to look at the implementation (or documentation) of the function to know what it does.

Magic Numbers

Replace Magic Numbers with named constants.
In general it is a bad idea to have raw numbers in your code. You should hide them behind well-named constants.

Encapsulate Conditionals

Instead of:

if (timer.hasExpired() && !timer.isRecurrent()) {

    // …

}

Create a method to encapsulate the conditional logic:

- (BOOL)shouldBeDeleted:(NSTimer *)timer {

    return timer.hasExpired() && !timer.isRecurrent();

}

if (shouldBeDeleted(timer)) {

    // …

}

Avoid Negative Conditionals

Negatives are just a bit harder to understand than positives.

Bad: if (!buffer.shouldNotCompact())

Good: if (buffer.shouldCompact()))

SRP

Single Responsibility Principle
Functions that do more than one thing should be converted into many smaller functions, each of which does one thing.

Constants versus Enums

Use enums rather than constants or #defines, enums are type checked.

Avoid Encodings

Names should not be encoded with type or scope information. Prefixes such as m_ or f are useless in today’s environments.
Polish notation is not a good fit for Cocoa.

Names Should Describe Side-Effects

Don’t hide side effects with a name.

Bad: getOos

Good: createOrReturnOos

Leave a Reply