These guidelines build on Apple's existing Coding Guidelines for Cocoa.
Unless explicitly contradicted below, assume that all of Apple's guidelines apply as well. Bold indicates a deviation from GitHub's conventions. Strikethrough indicates removal of a GitHub rule.
- Spaces, not tabs. 4 space width.
- End files with a newline.
- Make liberal use of vertical whitespace to divide code into logical chunks.
All method declarations should be documented.- Comments should be hard-wrapped at 80 characters.
- Any public documentation should use AppleDoc format
- Document whether object parameters allow
nil
as a value when appropriate. - Use
#pragma mark
s to categorize methods into functional groupings and protocol implementations, following this general structure:
#pragma mark - Lifecycle
+ (id)objectWithThing:(id)thing {}
- (id)init {}
#pragma mark - Properties
@dynamic someProperty;
- (void)setCustomProperty:(id)value {}
#pragma mark - Drawing
- (void)drawRect:(CGRect) {}
#pragma mark - Another functional grouping
#pragma mark - GHSuperclass
- (void)someOverriddenMethod {}
#pragma mark - NSCopying
- (id)copyWithZone:(NSZone *)zone {}
#pragma mark - NSObject
- (NSString *)description {}
- Never declare an ivar unless you need to change its type from its declared property.
Don’t use line breaks in method declarations.- Prefer exposing an immutable type for a property if it being mutable is an implementation detail. This is a valid reason to declare an ivar for a property.
- Always declare memory-management semantics
evenexcept onreadonly
properties that will be generated dynamically. However,readonly
properties that will be stored internally should have memory-management semantics declared. This distinguishes generated properties from properties that just are immutable. - Declare properties
readonly
if they are only set once in-init
. - Declare properties
copy
if they return immutable objects and aren't ever mutated in the implementation. - Don't use
@synthesize
unless the compiler requires it. Note that optional properties in protocols must be explicitly synthesized in order to exist. - Instance variables should be prefixed with an underscore (just like when implicitly synthesized).
- Don't put a space between an object type and the protocol it conforms to.
@property (attributes) id<Protocol> object;
@property (nonatomic, strong) NSObject<Protocol> *object;
- C function declarations should have no space before the opening parenthesis, and should be namespaced just like a class.
void GHAwesomeFunction(BOOL hasSomeArgs);
- Constructors should generally return
instancetype
rather thanid
. - Prefer C99 struct initialiser syntax to helper functions (such as
CGRectMake()
).
CGRect rect = {
.origin.x = 3.0,
.origin.y = 12.0,
.size.width = 15.0,
.size.height = 80.0,
};
- Don't access an ivar unless you're in
-init
,-dealloc
or a custom accessor. - Use dot-syntax when invoking idempotent methods, including setters and class methods (like
NSFileManager.defaultManager
). - Use object literals, boxed expressions, and subscripting over the older, grosser alternatives.
- Comparisons should be explicit for everything except
BOOL
s and pointer comparisons to nil. (i.e. don't doif (index)
with an NSInteger) - Prefer positive comparisons to negative.
obj == nil
is prefered over!obj
- Don't nest ternary operators.
- Long form ternary operators should be wrapped in parentheses and only used for assignment and arguments.
Blah *a = (stuff == thing ? foo : bar);
- Short form,
nil
coalescing ternary operators should avoid parentheses.
Blah *b = thingThatCouldBeNil ?: defaultValue;
- Separate binary operands with a single space, but unary operands and casts with none:
void *ptr = &value + 10 * 3;
NewType a = (NewType)b;
for (int i = 0; i < 10; i++) {
doCoolThings();
}
- Always surround
if
bodies with curly braces if there is anelse
. Single-lineif
bodies without anelse
should be on the same line as theif
. - All curly braces should begin on the same line as their associated statement. They should end on a new line.
- Put a single space after keywords and before their parentheses.
- No spaces between parentheses and their contents.
if (shitIsBad) return;
if (something == nil) {
// do stuff
} else {
// do other stuff
}
- Don't use exceptions for flow control.
- Use exceptions only to indicate programmer error.
- To indicate errors, use an
NSError **
argument, or failure block.or send an error on a ReactiveCocoa signal.
- Blocks should have a space between their return type and name.
- Block definitions should omit their return type when possible.
- Block definitions should omit their arguments if they are
void
. - Parameters in block types should be named unless the block is initialized immediately.
void (^blockName1)(void) = ^{
// do some things
};
id (^blockName2)(id) = ^ id (id args) {
// do some things
};
- Avoid making numbers a specific type unless necessary (for example, prefer
5
to5.0
, and5.3
to5.3f
). - The contents of array and dictionary literals should have a space on both sides.
- Dictionary literals should have no space between the key and the colon, and a single space between the colon and value.
NSArray *theShit = @[ @1, @2, @3 ];
NSDictionary *keyedShit = @{ GHDidCreateStyleGuide : @YES };
- Longer or more complex literals should be split over multiple lines (optionally with a terminating comma):
NSArray *theShit = @[
@"Got some long string objects in here.",
[AndSomeModelObjects too],
@"Moar strings."
];
NSDictionary *keyedShit = @{
@"this.key": @"corresponds to this value",
@"otherKey": @"remoteData.payload",
@"some": @"more",
@"JSON": @"keys",
@"and": @"stuff",
};
- Categories should be named for the sort of functionality they provide.
Don't create umbrella categories.Umbrella categories are acceptable for grouping convenience methods. - Category methods should
always be prefixed.be prefixed if they are part of a library that will be shared. - If you need to expose private methods for subclasses or unit testing, create a class extension named
Class+Subclass
.