Skip to content

Objective C Style Guide

Joel Fischer edited this page May 13, 2020 · 8 revisions

These guidelines build on the Apple Coding Guidelines for Cocoa.

Partially based on the Github, New York Times, and Dropbox style guides.

Whitespace

  • Spaces not tabs (4 spaces per indentation)
  • End files with a newline
  • Use whitespace to divide code into chunks
  • No trailing whitespace on lines

Comments

  • Block comments should only exist for generated documentation.
  • Inline comments should be used only if the time spent writing the comments is less than the time it would take someone with zero context to understand what you are doing. If you find yourself writing a lot of comments, the code should probably be broken apart or refactored for clarity.

Pragma

  • #pragma mark methods into logical clusters. Use #pragma mark - for major functionality groups, #pragma mark for minor functionality groups.

TODOs

  • Label TODO and FIXME comments with a name and date, follow the formatting shown below.
  • All FIXME comments must be fixed or deleted before a release.
// TODO: (Joel F.)[2015-03-22] Make sure we do the thing!

Imports

  • Order is: 1. Your own header (if in .m) 2. Framework headers 3. Local headers
  • Import alphabetically.
  • Use class forwarding in .h files whenever possible.

Declarations

Properties

  • Use strong properties only if exposing a mutable object, or one that does not conform to <NSCopying>. Prefer copy in other instances.
  • Properties should be declared nonatomic by default unless there is a very good reason to use atomic, which will be rare.
  • Properties should be accessed and set using dot-syntax.

Instance Variables

  • Collections should rarely, or never, be exposed publicly as mutable, they should also be read-only as much as possible. Collections that are mutable in the implementation should be exposed as so:
file.h

@property (nonatomic, readonly) NSArray *array;

file.m

@property (nonatomic) NSMutableArray *mutableArray;

- (NSArray *)array {
    return [self.mutableArray copy];
}
  • Always create properties instead of iVars. Private properties should be generated in an interface extension.
  • iVars should be prefixed with an underscore, like implicitly synthesized ones.
  • Access properties by iVar only if in -init, -dealloc, or a custom accessor.

Local Variables

  • Always initialize local variables, they will not be automatically initialized to nil or 0.

Methods

  • If a private method can be a class method instead of an instance method, it should be a class method.
  • Private methods should be prefixed with the project prefix sdl.
+ (void)sdl_privateClassMethod {}
  • Protected methods should be declared in a class extension that subclasses implement and other classes do not.

Constants

  • Prefer constants to inline string literals and numbers to more easily change them if necessary. Constants should be declared as static constants that are exported if public, and not #define.

Expressions

  • Access properties and structs by dot-syntax, everything else (including idempotent methods) via bracket syntax.

Literals

  • Binary operands should be separated with a space, unary and casts with no space.
for (int i = 0; i < 10; i++) {}
void *thing = &thing;
SuperThing newThing = (SuperThing)subThing;
  • NSString, NSDictionary, NSArray, and NSNumber literals should be used whenever possible. When turning a non-NSNumber number variable into an NSNumber, box the number with @().
NSString *string = @"string";
NSArray *array = @[ @1, @2, @3 ];
NSDictionary *dict = @{ @"key": value };
NSNumber *number = @42;
  • Complex dictionary and array literals should be split across multiple lines.
NSDictionary *complexDict = @{
	@"key1": value1,
	@"key2": value2,
	@"key3": value3
};

Enums

  • To declare enumerations, use NS_ENUM. To declare options (bitmasks) use NS_OPTIONS.
typedef NS_ENUM(NSInteger, UITableViewCellStyle) {
    UITableViewCellStyleDefault,
    UITableViewCellStyleValue1,
    UITableViewCellStyleValue2,
    UITableViewCellStyleSubtitle
};
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
};

Switch

  • For case blocks that are one line, you may omit braces. This will usually only happen if break is the only statement.
  • For case blocks that contain more than one line, wrap the lines in braces.
  • When falling through a case statement, explicitly mark it with the comment //fallthrough
  • If possible, default should be an assertion.
switch(someEnum) {
	case someEnumValue: {
		// Do many things
	} break;
	case someEnumValue2: // Fallthrough
	case someEnumValue3: {
		// Do a few more things
	} break;
	default: NSAssert("Unknown enum value %@", @(someEnum));
}

Conditionals

  • Conditionals should always contain braces.
  • Comparisons should always be explicit except for BOOL values. BOOL values are actually a signed char, and explicit comparisons can lead to incorrect results in certain cases, such as setting a BOOL to the result of an array's length.
  • Ternary operators should only be used when they improve clarity in assignments and arguments. They should be wrapped in parenthesis.
  • Coalescing ternary operators should not use parenthesis.
if (someObject != nil) {
	// Do the thing
} else if (someBool) {
	// Do the other thing
} else {
	// Do the last thing
}

NSString *someString = (isTrue ? @"YES" : @"NO");
NSString *someOtherString = optionalValue ?: defaultValue;

Exceptions and Errors

  • Never use exceptions for flow control, only for programmer error.
  • Use NSError to indicate all other fault types. To indicate that a method may error, receive an NSError ** parameter.
  • Make sure to test for nullability on the error argument before setting it.

Preventing Bugs

  • Only iterate over immutable collections. Convert mutable collections to immutable ones