Some guidance from Apple:
- The Objective-C Programming Language
- Cocoa Fundamentals Guide
- Coding Guidelines for Cocoa
- iOS App Programming Guide
Dot-notation should always be used for accessing and mutating properties. Bracket notation is preferred in all other instances.
For example:
view.backgroundColor = [UIColor orangeColor];
[UIApplication sharedApplication].delegate;
Not:
[view setBackgroundColor:[UIColor orangeColor]];
UIApplication.sharedApplication.delegate;
Use #pragma marks to categorize methods into functional groupings and protocol implementations, following this general structure:
#pragma mark Properties
@dynamic someProperty;
- (void)setCustomProperty:(id)value {}
#pragma mark Lifecycle
+ (id)objectWithThing:(id)thing {}
- (id)init {}
#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 {}
Use the following documentation style for methods and properties:
/*
* A concise description of the method
* with a focus on what it does, rather than
* how it works.
*
* @param someString A string that contains numbers
* @return strings that were delimited by numbers
*/
- (NSArray *)componentsSeparatedByNumbers:(NSString *someString);
/// Employee name
@property (nonatomic) NSString *name;
Both of these will show up when alt
-clicking a method or property usage.
- Indent using 4 spaces. Never indent with tabs. Be sure to set this preference in Xcode.
- Method braces and other braces (
if
/else
/switch
/while
etc.) always open on the same line as the statement but close on a new line.
For example:
if (user.isHappy) {
//Do something
}
else {
//Do something else
}
- One blank line between methods
- Whitespace within methods should separate functionality, but often there should probably be new methods.
- Maximum one blank line separation
@synthesize
and@dynamic
should each be declared on new lines in the implementation.
Conditional bodies should always use braces even when a conditional body could be written without braces (e.g., it is one line only) to prevent errors.
For example:
if (!error) {
return success;
}
Not:
if (!error)
return success;
or
if (!error) return success;
The Ternary operator, ? , should only be used when it increases clarity or code neatness. A single condition is usually all that should be evaluated.
For example:
result = a > b ? x : y;
Not:
result = a > b ? x = c > d ? c : d : y;
When methods return an error parameter by reference, switch on the returned value, not the error variable.
For example:
NSError *error;
if (![self trySomethingWithError:&error]) {
// Handle Error
}
Not:
NSError *error;
[self trySomethingWithError:&error];
if (error) {
// Handle Error
}
In method signatures, there should be a space after the scope (-/+ symbol). There should be a space between the method segments.
For Example:
- (void)setExampleText:(NSString *)text image:(UIImage *)image;
In method implementations, the first curly brace should be positioned on the same line as the method signature. This creates a compact .m
file when viewed with method bodies collapsed.
- (void)setExampleText:(NSString *)text image:(UIImage *)image { ... }
Variables should be named as descriptively as possible. Single letter variable names should be avoided except in for()
loops.
Asterisks indicating pointers belong with the variable, e.g., NSString *text
not NSString* text
or NSString * text
, except in the case of constants.
Property definitions should be used in place of naked instance variables whenever possible. Direct instance variable access should be avoided except in initializer methods (init
, initWithCoder:
, etc…), dealloc
methods and within custom setters and getters.
For example:
@interface NYTSection: NSObject
@property (nonatomic) NSString *headline;
@end
Not:
@interface NYTSection : NSObject {
NSString *headline;
}
Apple naming conventions should be adhered to wherever possible, especially those related to memory management rules (NARC).
Long, descriptive method and variable names are good.
For example:
UIButton *settingsButton;
Not
UIButton *setBut;
If Xcode can automatically synthesize the variable, then let it. Otherwise, the backing instance variables for these properties should be camel-case with the leading word being lowercase and a leading underscore.
For example:
@synthesize descriptiveVariableName = _descriptiveVariableName;
Not:
id varnm;
When using properties, instance variables should always be accessed and mutated using self.
. This means that all properties will be visually distinct, as they will all be prefaced with self.
. Local variables should not contain underscores.
When they are needed, comments should be used to explain why a particular piece of code does something.
Block comments should generally be avoided, as code should be as self-documenting as possible.
init
methods should be structured like this:
- (instancetype)init {
self = [super init]; // or call the designated initalizer
if (self) {
// Custom initialization
}
return self;
}
NSString
, NSDictionary
, NSArray
, and NSNumber
literals should be used whenever creating immutable instances.
Put a space between the outer [ ]
and { }
.
For example:
NSArray *names = @[ @"Brian", @"Matt", @"Chris", @"Alex", @"Steve", @"Paul" ];
NSDictionary *productManagers = @{ @"iPhone" : @"Kate", @"iPad" : @"Kamal", @"Mobile Web" : @"Bill" };
NSNumber *shouldUseLiterals = @YES;
NSNumber *buildingZIPCode = @10018;
Not:
NSArray *names = [NSArray arrayWithObjects:@"Brian", @"Matt", @"Chris", @"Alex", @"Steve", @"Paul", nil];
NSDictionary *productManagers = [NSDictionary dictionaryWithObjectsAndKeys: @"Kate", @"iPhone", @"Kamal", @"iPad", @"Bill", @"Mobile Web", nil];
NSNumber *shouldUseLiterals = [NSNumber numberWithBool:YES];
NSNumber *buildingZIPCode = [NSNumber numberWithInteger:10018];
When accessing the x
, y
, width
, or height
of a CGRect
, always use the CGGeometry
functions instead of direct struct member access.
For example:
CGRect frame = self.view.frame;
CGFloat x = CGRectGetMinX(frame);
CGFloat y = CGRectGetMinY(frame);
CGFloat width = CGRectGetWidth(frame);
CGFloat height = CGRectGetHeight(frame);
Not:
CGRect frame = self.view.frame;
CGFloat x = frame.origin.x;
CGFloat y = frame.origin.y;
CGFloat width = frame.size.width;
CGFloat height = frame.size.height;
Constants should be declared as static
constants and not #define
s unless explicitly being used as a macro.
For example:
static NSString * const NYTAboutViewControllerCompanyName = @"The New York Times Company";
static const CGFloat NYTImageThumbnailHeight = 50.0;
Not:
#define CompanyName @"The New York Times Company"
#define thumbnailHeight 2
When using enum
s, use NS_ENUM()
Example:
typedef NS_ENUM(NSInteger, NYTAdRequestState) {
NYTAdRequestStateInactive,
NYTAdRequestStateLoading
};
Private properties should be declared in class extensions (anonymous categories) in the implementation file of a class.
For example:
@interface NYTAdvertisement ()
@property (nonatomic, strong) GADBannerView *googleAdView;
@property (nonatomic, strong) ADBannerView *iAdView;
@property (nonatomic, strong) UIWebView *adXWebView;
@end
Since nil
resolves to NO
it is unnecessary to compare it in conditions. Never compare something directly to YES
, because YES
is defined to 1 and a BOOL
can be up to 8 bits.
This allows for more consistency across files and greater visual clarity.
For example:
if (!someObject) {
}
Not:
if (someObject == nil) {
}
For a BOOL
, here are two examples:
if (isAwesome)
if (![someObject boolValue])
Not:
if ([someObject boolValue] == NO)
if (isAwesome == YES) // Never do this.
If the name of a BOOL
property is expressed as an adjective, the property can omit the “is” prefix but specifies the conventional name for the get accessor, for example:
@property (assign, getter=isEditable) BOOL editable;
Singleton objects should use a thread-safe pattern for creating their shared instance.
+ (instancetype)sharedInstance {
static id sharedInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [[self alloc] init];
});
return sharedInstance;
}
This will prevent possible and sometimes prolific crashes.
The physical files should be kept in sync with the Xcode project files in order to avoid file sprawl. Any Xcode groups created should be reflected by folders in the filesystem. Code should be grouped not only by type, but also by feature for greater clarity.
When possible, always turn on "Treat Warnings as Errors" in the target's Build Settings and enable as many additional warnings as possible. If you need to ignore a specific warning, use Clang's pragma feature.
If ours doesn't fit your tastes, have a look at some other style guides: