Objective-C Style Guide

This document contains a set of recommended guidelines, conventions, and best practices for writing code in our iOS code base. The main motivation for this guide is to improve the readability of the code base. Remember that code is read much more often than it is written, and that 80% of the lifetime cost of software goes to maintainence.

Note that the purpose of this guide is not to convince any one that whatever listed below is the best way of doing something. The idea is to keep a set of recommended guidelines for everyone to follow in order to make the code more consistent, understandable, and less prone to unobvious pitfalls.

Note: Suggestions for improvements are highly encouraged.

Formatting / Conventions

Note: Please take a look and familiarize yourself with Google’s Objective-C Style Guide. For things not specified below, we will try to follow their conventions.

Whitespaces

Space only. 4-space indents.

Make sure you have Automatically trim trailing whitespace and Including whitespace-only lines enabled in Xcode.

Method Declarations

We will go with the default template Xcode uses: no spacing except between parameters and the one space after the -.

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    ...
}

Control flow statements (Conditions / Loops / etc.)

Brackets go on the same line as the conditions, e.g.

if (foobar) {
    ...
} else {
    ...
}
for (foo; foo; foo) {
    ...
}

Single line control flow statements

Should still have braces

if (foobar) {
    ...
} else {
    ...
}

Naming

Please take a look at Apple's Coding Guidelines espcially on how methods should be named. e.g. use - (NSSize)cellSize instead of - (NSSize)getCellSize.

Pointer declarations

For pointers, place the star in front of the variable name. e.g. NSString *foo

Use literals

Use Obj-C literals for dictionaries, arrays and numbers whenever possible: e.g. @42 instead of [NSNumber numberWithInt:42], and

NSDictionary *dictionary = @{
    @”k1” : @”v1”,
    @”k2” : @”v2”,
};

instead of [NSDictionary dictionaryWithObjectsAndKeys:@”v1”, @”k1”, @”v2”, @”k2”, nil] BAD

Only use dot notations for declared @properties

Use dot notations only for declared properties and structs.

Do NOT do stuff like foobar.release or foobar.count. BAD

Reasoning: while the dot syntax is more or less just syntactic sugar around getter/setter calls, it is idiomatic to use them only for properties.

Prefix instance vars with _

ivars should always be prefixed by an underscore (e.g. NSString *_foobar)

Reasoning: default backing ivars for properties are also prefixed by underscore. We should be consistent.

Be explicit about the qualifiers when declaring properties

Mark them as nonatomic/atomic, retain/assign explicitly.

Reasoning: makes life easier when migrating to/from ARC (where default is strong instead of assign)

Annotate your weak ivars

If you are not using ARC, you should still annotate ivars that are weak. (in ARC, obviously you would need the __weak qualifier.) By default, we will assume ivars that are not marked as weak to be retained.

e.g. id<SomeDelegate> _delegate; // weak ref

Never use public ivars

External callers should never mutate ivars directly. Provide getters/setters for external callers.

Private ivars go in @implementation block

Private ivars should go under the @implementation block. e.g.

@implementation
{
    NSString *_foobar;
}

Sort your #imports alphabetically

Keep #imports sorted alphabetically. Start with local imports, (for .m files, import its own headers first). followed by global imports. e.g. for DBFoo.m:

#import "DBFoo.h"
#import "DBFoo+Protected.h"

#import "DBAnotherFile.h"
#import "DBSomeOtherFile.h"
#import <CoolFramework/Header.h>
#import <FoobarFramework/Foo.h>

#pragma mark your code and group code by functionalities

Use #pragma mark extensively to designate logical clusters of methods, such as those methods that implement a particular protocol, or the getter/setters of a particular object. For sections vs. subsections, you can use #pragma mark - to create dividers in Xcode’s symbol navigator. For example, in a table view controller you may find pragma marks like the following:

#pragma mark - Lifecycle // for init and dealloc methods
#pragma mark - Appearance
#pragma mark view initializations
#pragma mark view utilities
#pragma mark - UIViewController overrides
#pragma mark - UITableViewDataSource
#pragma mark - UITableViewDelegate

To keep things easy to find, methods should be grouped by functionality rather than scope. For example, a private class method can be in between two public instance methods.

dealloc/init

Always place them first - dealloc should go first (and ivars should be released in the same order as they are declared).

Scope your switch cases, and avoid catch-alls

For larger switch-case blocks, make each case block into a scoped block, e.g.

switch (foo) {
    case 0: {
        ...
    }
    break;
    ...
}

Avoid using default as catch-alls if possible (e.g. don’t use default just to omit the last case). When possible, default should be an error case that contains an NSCAssert or DBLogError.

Prefix your private methods (and methods added by categories)

Prefix them with db_. e.g. - (void)db_flushQueue

Reasoning: makes it easy to tell if a method is private or not (e.g. when reading a diff that modifies a method, it is nice to know right away if the method is public/private). It also makes it less likely for subclasses to accidentally override a private method - because Apple uses _ to prefix their private methods.

Make private methods class methods if they don’t depend on instance state

If a private method doesn’t use any ivar, just make it a class method.

Reasoning: it is much easier to reason through a method if I don’t have to think about the states it could be in.

TODOs/FIXMEs

Label your TODOs and FIXMEs with names and dates:

TODO:(rich) 2013-09-13 finish the style guide!

Please follow the prefix style TODO:(<name>) <date> consistently to make things easier to grep.

Use FIXMEs for urgent things that need to be fixed before pushing.

Use static consts for constants

Use static consts instead of #defines for constants.

static const CGFloat kFooBar = 123.0;

Reasoning: it respects scope, is type-safe, and is loaded as a symbol and therefore easier to access through debugger.

Always use NSUIntegers/NSIntegers over int (and CGFloat over float)

Unless certain API libraries specify exact types you should use.

Reasoning: Most of the Cocoa libraries prefer NSIntegers, so it is best to pass in what they expect when crossing API boundaries. Since int varies in size between architectures, this is more reliable for developing against the iOS libraries.

Enum declarations

As introduced in 2012’s WWDC, you should use NS_ENUM to declare your enums.

typedef NS_ENUM(NSInteger, UITableViewCellStyle) {
    UITableViewCellStyleDefault,
    UITableViewCellStyleValue1,
    UITableViewCellStyleValue2,
    UITableViewCellStyleSubtitle
};

To make autocomplete easier, you should also name your constants <enum name><variant>.

Reasoning: NS_ENUM gives stronger type checking, code completion.

Bitmask constants

Similar to NS_ENUM, use the new NS_OPTIONS construct in iOS 6, e.g.:

typedef NS_OPTIONS(NSUInteger, UIViewAutoresizing) {
    UIViewAutoresizingNone                 = 0,
    UIViewAutoresizingFlexibleLeftMargin   = 1 << 0,
    UIViewAutoresizingFlexibleWidth        = 1 << 1,
    UIViewAutoresizingFlexibleRightMargin  = 1 << 2,
    UIViewAutoresizingFlexibleTopMargin    = 1 << 3,
    UIViewAutoresizingFlexibleHeight       = 1 << 4,
    UIViewAutoresizingFlexibleBottomMargin = 1 << 5
};

Prefix your class names with DB e.g. DBFoobarViewController

Reasoning: Because ObjC doesn't support namespaces..

Prefer enumerators over looping by indexes

Use block-based methods like enumerateObjectsUsingBlock, or fast enumerations, e.g.

for (id setObject in collection) {
}

Reasoning: reduces the amount of context a reader needs to keep in his/her head. The reader doesn't have to worry about the correctness of index variables. Enumerators are also more performant in general.

Best Practices / Pitfall Avoidance

Always use NSCAsserts for assertions

We will use NSCAsserts instead of asserts or NSAsserts for doing assertions.

Reasoning: NSAssert is a macro that actually internally references self. In other words, when used in a block, you may unintentionally cause the block to retain self. We could alternatively use NSAsserts in cases where we are actually okay with using self, but since NSAssert and NSCAssert do roughly equivalent things (they both include file name, method name + line number, though NSCAssert does not print the actually type of self), we will keep things simple and always use NSCAssert.

Memory management policy (non-ARC)

We will conform with Cocoa’s policy where "Cocoa’s ownership policy specifies that received objects should typically remain valid throughout the scope of the calling method.” In other words, we should make sure that objects returned by a public method will not just disappear due to the caller then calling something else in the object.

For example, when a caller does something like this:

NSString *foo = a.foo;
a.foo = @”blah”;
NSLog(@”foo = %@”, foo);

We should have the implementation of setFoo: and foo ensure that the local variable foo remains valid till the end of the caller's scope and the NSLog doesn't crash.

Autorelease when re-assigning an ivar you own (non-ARC)

To conform with the memory management policy mentioned above, we will always autorelease instead of release ivars when re-assigning. e.g.

- (void)setFoo:(NSString *)foo
{
    [_foo autorelease];
    _foo = [foo retain];
}

Reasoning: this is to avoid the case mentioned in the example above, where the caller assigns something to a local variable and then the object gets deallocated.

There are three workarounds for these issues: 1. we can make the local variable retain-autorelease the result of the getter; 2. we can make getters return something that’s retain-autoreleased; 3. or we can do what the above suggested.


The later two conform to Cocoa’s policy “Cocoa’s ownership policy specifies that received objects should typically remain valid throughout the scope of the calling method.” and the last one suggested is somewhat more robust.

When using retain @properties in non-ARC, always provide a custom setter (non-ARC)

The setter should follow the same semantics as the autorelease-then-retain rule above, e.g.

@property (nonatomic, retain, setter=setFoo:) NSNumber *foo;

Reasoning: this is similar to the rule above. The issue is that the default synthesized setter does not conform to the autorelease-then-retain pattern, so the example in the previous rule would break.

Memory ownership pitfall (non-ARC)

When returning an object from a Cocoa collection (e.g. NSArray), you should do a retain-autorelease. e.g.

- (id)foo
{
    return [[_someArray[0] retain] autorelease];
}

Similarly, if you are using an object from something that is later released, the object may be released as well, so you need to protect it from being released.

Reasoning: when removing objects from collections like NSArrays, those objects get released right away. So in cases where a caller is holding onto an object returned from these methods, if we then remove that object from the array, that reference will no longer be valid.

Always copy blocks when stored

When you wish to reference a block literal after the scope of a method (e.g. by storing it as an ivar), you should explicitly copy the block by calling, e.g. [theBlock copy].

Reasoning: As an optimization, blocks and their storage starts out on the stack. Therefore, if you wish to reference a block after the current scope returns, you should copy it to the heap by calling [theBlock copy] explicitly.

Some notable rules from the Google style guide

Autorelease at creation time of temporary objects (non-ARC)

Reasoning: Unless you foresee a performance hit, you should autorelease when creating a local variable. Otherwise later changes may do a return prior to the release or add a branch that omit the release, causing a leak. For memory-aggresive code paths, wrap them with a tighter @autoreleasepool block to drain the autoreleased objects.

Avoid accessors during init and dealloc whenever practical

Reasoning: To avoid triggering side effects of setters and getters.

Always copy NSStrings

Reasoning: Use copy instead of retain for NSStrings passed in from external callers in case they are passing in NSMutableStrings.

Never convert general integral values / object pointers to BOOL

Common mistake: casting the length of an array into a BOOL

Reasoning: even if the number is > 0, it may still cast to NO if the low bits are 0.

Do NOT use @properties for private states

Instead of declaring @propertys in your .m file, just use ivars.

Reasoning: properties don’t really give you much other than the setter/getters. and, as the rule above mentioned, you should use custom setters for retained properties anyway. The only thing you get may be KVO, which you shouldn’t need for private states.

One exception being the use of atomic properties, which you should use sparingly.

In dealloc, clean up delegates that point to you + anything you are an observer of

If an object has been set as the delegate/observer of other objects (e.g. notification center), you should nil them out in dealloc.

NOTE: Even in ARC code, where delegate properties should be weak, it is still important to nil out a delegate pointer pointing to self from a system class. That is because most of these are still compiled as assign.

Reasoning: otherwise, if the object that has you as the delegate later tries to talk to you, it would crash.

Always initialize your local variables

ivars are automatically initialized to nil or 0, so you do not need to explicitly nil them out, but not local variables. So you should always initialize them to something manually.

Put protected methods in a separate header file

For instance, for protected methods in DBFooViewController, we should place the signatures in a separate file DBFooViewController+Protected.h. The .m file should import both the DBFooViewController.h and DBFooViewController+Protected.h files.

The methods should be declared in a class extension and not a category, and the implementation should still belong to the primary implementation for the class.

Reasoning: this way when callers import your header, they won’t get the protected methods and won’t accidentally call protected methods. Only subclasses should have to import the protected header.

In View Controllers, don’t touch the view until viewDidLoad

Calling self.view will implicitly load the view, which is usually not necessary.

Prefer blocks over target-selector patterns for callbacks

For simple callback patterns, we prefer blocks over the target-selector delegate pattern.

e.g. instead of using an UIActionSheet, setting the delegate and then checking in the delegate which action sheet and which button is clicked, you should just use the block-based alternative that assigns a callback block to each button.

Reasoning: helps reduce code separation, e.g. imagine some async op with a completion handler. Instead of having a separate delegate method that implements the handler, it is much clearer what happens if you do something like:

[op startWIthCompletionHandler:^() {
    // ... stuff to be done after the op finishes ...
 }];

Add careful documentation on classes/methods/ivars that support threading

By default, we will assume all methods are only going to be called from the main thread. If a method is expected to be called from a background thread (e.g. certain Apple notifications like ALAssetsLibraryChangedNotification), make sure to add comments accordingly and add assertions if possible (e.g. DBAssertMainThread).

Similarly, we will assume all instance variables to be accessed only via the main thread. If certain ivars do need to be shared across threads (or are accessed exclusively from a specific dispatch queue), make sure you add comments accordingly.

For classes that are designed to have a thread-safe interface, make sure you add documentations around how things work.

Avoid atomic unless absolutely necessary

By default, all properties are atomic, so you should mark them explicitly as nonatomic.

Reasoning: making a property atomic means all setters/getters are synchronized and has the perf hit of being so. Also, it is rare for atomic to actually be useful - most of the time if your variables need to be shared across thread (which is hopefully very rare), you probably don't just want the setting and accessing of the individual variables to be protected.

Prefer GCD over performSelector

And you should almost never use performSelectorInBackground.

Reasoning: the reasoning is pretty similar to why we prefer blocks over target-selectors. This also makes the code easier to reason about as we won’t be forced to have separate methods that are called on a background thread.

Try to avoid unnecessary imports in headers

Use forward declaring instead if possible e.g. @class DBFoo.

Reasoning: reduce compile time and unnecessary dependencies

Always document designated initializers

Identify clearly your class's designated initializers that other initializers call through.

Reasoning: so subclasses can just override those to guarantee that the subclass' initializer is called.

Always override superclass’s designated initializers

If callers shouldn’t call them any more, make them throw an assert.

Observer selectors should take in a NSNotification argument

[[NSNotificationCenter defaultCenter] addObserver:self
                                         selector:@selector(db_updateStuffWithNotification:)
                                             name:@"SomeNotificationName"
                                           object:theSender];

Reasoning: while it is not required (e.g. supplying a selector that doesn't take in any argument will still work), doing it this way makes it obvious to the reader that the method is called as a result of a notification.

Blocks & retain cycles (ARC)

Blocks implicitly creates strong references to self if they access self or an ivar by reference.

In other words, it is possible to accidentially introduce permanent retain cycles when using blocks. A common scenario is, for instance, when you use a BlockAlertView and give it an observer block that retains self. Assuming that self retains the alert view, this may cause a retain cycle where self -> alert view -> block -> self.

(Quick reference from Apple regarding when things are retained by blocks: Blocks and Variables.)

To avoid these cycles, we can do what is typically known as the "strong-weak dance":

__weak DBFoo *weakSelf = self;
[_someRandomViewIOwn setObserverBlock:^{
    DBFoo *strongSelf = weakSelf;
    // NOTE: strongSelf may point to nil if weakSelf is already nil'ed out prior to the block being called!
    [strongSelf doSomeStuff];
}];

Reasoning: The idea is that, by using weakSelf, the block no longer retains self. However, it is still possible for weakSelf to get nil'ed out before the block is invoked. To make things even worse, if the object may be touched by multiple threads, it is possible for weakSelf to nil out in the middle of the block!

To prevent self from disappearing in the middle of the block, we added strongSelf to artificially create a strong reference to weakSelf. While strongSelf may still point to nil, it will be consistent throughout the scope of the block, so you don't have to worry about it disappearing arbitrarily.

You also should not, however, abuse this pattern. A lot of times when you just want to, say, run a block later (e.g. animations, dispatch_after), you do NOT need to do this - it is fine so long if those retain cycles are temporary.

Blocks & retain cycles (non-ARC)

In non-ARC land, we do not have weak references that nil themselves out, so the alternative will be doing something like __block to mark variables are block variables. e.g.

__block DBFoo *weakSelf = self;
[_someRandomViewIOwn setObserverBlock:^{
    // NOTE: if self is deallocated before this is invoked, deref'ing weakSelf will crash!
    [weakSelf doSomeStuff];
}];

Since weakSelf will not nil itself out here, for objects that do this, if you think the object holding onto the block may have a longer life time than self, you should make sure you nil out the observer block in dealloc (similar to what you should do in a delegate pattern).

Common Bugs

Deallocated self

Another scenario where self may get nil'ed out

TODO:(rich) 2013-09-20 fill in the explanations for the rest of these bugs..

Categories & missing targets

Rotation and superview resizing

Manipulating the UI from background thread

When creating your own thread, make sure to create @autoreleasepools

e.g. if you are creating a thread that just continuously iterate on a while loop, at the minimum, the pool should drain after each iteration.

When overriding + (void)initialize, check to make sure the class matches

For example:

+ (void)initialize
{
    if (self != [TheClass class]) return;
    …
}

Reasoning: If subclasses didn’t override the method, the superclass’s implementation may fire unnecessarily.

When overriding superclass’s methods, don’t forget to call super

Unless you really want to override the existing behaviors, don’t forget to call the original implementation. Especially for UIKit classes

When overriding isEqual:, override hash as well

Always check respondsToSelector for optional delegate methods

Always check if a block is non-nil before calling it

Accessing backing ivars of atomic properties

Accessing the backing ivar will bypass the lock that synchronizes its getter/setters.

Good General Engineering Practices

Document your hacks

Make sure people understand why your hacks are needed! If people are later modifying your code or trying to reuse your code for other platforms, they will need to understand your reasoning so they can determine whether the hacks are still relevant. When developing against frameworks we do not control, it is not unlikely that hacks needed for one version will break or become irrelevant in the next.

When to write comments

A good rule of thumb is to consider the amount of time it takes for a person with zero context to understand/modify your code with vs. without comments.

Let's call the amount of time needed to write your comments A, and the amount of time need for a person to understand/modify your commented code B vs. uncommented code C. Please take the time to add comments if A + N*B < N*C - where N is the number of people who will read your code. =)

Also remember that your code is a type of documentation and is meant to be read by fellow human beings! When you find yourself writing a lot of comments about a chunk of code, you should also consider rearchitecting or breaking down the code.

Keep your methods small and focused

Try to keep your methods short and easy to reason about. Break methods up by functionalities!

Name your methods by the functionalities they provide

Method names should reflect what they do instead of what is calling them.

Expose as little as possible in public interfaces

Consumers of a class should only be concerned with what the class promises to do. The more internal details you expose, the more things are likely to break when you modify the implementation of your code.

When possible, properties should be readonly. Or better yet, don’t expose them at all!

Avoid boolean traps when creating APIs

When creating new methods, try to make it so readers do not have to dig into the documentation or implementation to figure out what something means.

For instance, do NOT do stuff like: - (void)refresh:(BOOL)animated; BAD. Although it is clear in the implementation that the flag is referring to whether the refresh must happen with animation, in the caller side, you will see code that looks like this: [foobar refresh:YES] BAD, where it is impossible to figure out by reading what the parameter refer to.

To mitigate this, you should name your methods so the word prior to the param indicates what it is expecting. To be even clearer, you may also use an enum for the parameter. e.g. - (void)refreshWithTransitionType:(DBFoobarTransitionType)transitionType;.

A pretty good read on this subject: hall of api shame: boolean trap.

Document what your code does not support

It is impossible to design things to support every foreseeable use case, but you should try to document any known issues. For instance, if a view controller does not lay out its subviews properly in landscape mode, leave a comment so people wishing to reuse it later will know.

Consolidate casts when appropriate

If a property declared as a more generic type is known to be of a specific subclass, redeclare the property as the specific type and implement the getter to consolidate the cast in one location, rather than litering casts throughout the code.

Reduce scope of variables

When reading code, it is usually best if variables are declared and used in the smallest scopes possible, so it is easier to read and reason through the effects of the variables (where they are used, modified, etc.).