##BoldRocket Objective-C Style Guide
This style guide serves to outline the coding conventions and style for all Bold Rocket Objective-C projects. The style guide should always be adhered to, even in the case of small proof of concepts or prototype applications.
The aim of this style guide is to standardise the way in which Objective-C is written, which subsequently reduces friction in reading it, making it more maintainable and therefore of a better quality.
The guide does not aim to define an applications architecture or any implementation details, these are domain specific problems which should be driven by the software architects and developers.
- Cocoa Coding Guidelines
- objc.io
- NSHipster
- iOS Dev Weekly
- Github Trending Objective-C Repositories
- NSBlog
- Xcode Project
- Header Organisation
- Implementation Organisation
- Types
- Variables
- Classes and Methods
- Properties
- Delegates
- Localisation
- Constants
- Initialization
- Conditionals
- Future Revisions
-
The underlining file and folder system should match the project structure inside of Xcode. If a group is created in Xcode an underlining folder should exist in the same place on the file system.
-
The Xcode project structure should be taken on a case by case basis but for "larger" projects a base project should include the following:
-
Controls (buttons, customised navigation controllers etc.)
-
User Journey (functional view controllers & views)
-
Data Access (object models, import routines, persistence stack etc.)
-
Web Service (configuration, end point definition, base request / response handlers etc.)
-
Models (plain old objects, business objects, data objects etc.)
-
Utilities (class categories, utility classes etc.)
-
Resources (fonts, pdfs etc.)
-
Xcassets (images)
-
Reference Data (json files, csv etc.)
-
Vendor (3rd party code, frameworks, libraries)
-
Xcassets, where available, should be used to manage image assets.
-
Image files should be descriptive of their screen function but should avoid visually describing their look. Filenames should be all lower case and spaces in file names should be replaced with hyphens.
Example
-
The Application Delegate should be called “AppDelegate” in all projects, there’s no requirement to rename this to be application specific.
-
XIB files should not have “Controller” as part of their file name but can optionally include “View” or “Window”.
Example
LoginView.xib
Register.xib- All class file names should start with a capital letter, along with all Xibs and Storyboard files.
Example
LoginViewController.m
WebServiceInterface.h- Projects should use the bundle ID in the format of com.boldrocket.[Client][Programme][Project] this helps keep naming conventions consistent across the provisioning portal.
Example
com.boldrocket.XYZGlobalProgrammeLocalProject- For frameworks and reusable classes class level prefixes should be used to avoid collisions – as per Apple guidelines 3 letters or more should be used for 3rd party libraries.
Example
BRTLoginViewController.m
RDNUrlCache.m-
Avoid declaring methods in the header which are not publicly required.
-
Set
IBOutletsin the header file, this makes referencing easy and consistent. -
Avoid
#importing in header files unless explicitly required. Instead opt for forward class declaration via@class. This leads to cleaner headers and faster compile times. The@classreference should be declared below the#importstatements but above the@interfacestatement with a blank line separating each category. -
Constants should always be set between
#import(below@class) and@interface.
Example
#import <UIKit/UIKit.h>
#import <Foundation/Foundation.h>
@class MBProgressHUD;
extern NSString * const kLoginReference;
@interface LoginViewController : UIViewController- Always import framework headers first, followed by a blank line and then the class specific imports.
Example
#import <UIKit/UIKit.h>
#import <Foundation/Foundation.h>
#import <CoreLocation/CoreLocation.h>
#import "LoginViewController.h"
#import "IntroductionViewController.h"-
Constants and
typdefshould always be set between#importand@implementationreferences. -
All definitions stored at the top of the implementation file should be logically grouped together and consistent, with a single line between each "block".
Example
#import <UIKit/UIKit.h>
#import <Foundation/Foundation.h>
#import <CoreLocation/CoreLocation.h>
NSString * const kkLoginReference = @"loginRef";
NSString * const kLogoutReference = @"logoutRef";
typedef void (^BRLoginStatusBlock)(BRLoginStatus status);
typedef enum {
BRTLoginStyleLight,
BRTLoginStyleDark
} BRTLoginStyle;
@implementation LoginViewController- Conditional and loop bracing should start on the same line and end on a new line.
Example
if (user.isLoggedIn) {
...
}- Method level braces should always be included on their own line.
Example
- (IBAction)submitLoginCredentials:(UIButton *)sender
{
...
}- Always use braces for
if/for/while/elseetc. statements. Readability and consistency are a fair trade-off in all cases, even in the case of early returns.
Example
if (!user.isValid) {
...
}- Use Pragma mark to separate method sets, the below set provides a breakdown of the default set which should be used, additional ones can be added as required.
- Lifecyle –
viewDidLoad,init,deallocetc. - Navigation – For links to other Views / Storyboards -
prepareForSegue,performSegueetc. - Public – All public methods required for the class to function.
- Actions –
IBActions - Protocols – named individually by their class name
- Private / Utility – For any private methods and class specific utility methods
Example
#pragma mark – Lifecycle
- (void)viewDidLoad
{
...
}
#pragma mark - Navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
...
}
#pragma mark – Public
- (void)submitLoginCredentials
{
...
}
#pragma mark – Actions
- (IBAction)submitLoginCredentials:(id)sender
{
...
}
#pragma mark – UITableViewDelegate
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
...
}
#pragma mark – UITableViewDataSource
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
...
}
#pragma mark – Private / Utility
- (void)clearFormTextFields
{
...
}- Use method returns early to help keep conditional logic clear.
Example
- (void)processRequest
{
if (!user.isValid) {
return;
}
// continue with flow
}- There should only be a one line space between methods for consistency as well as a one line space between the final method brace and the
@enddirective.
Example
- (void)hideAdditionalTextFields
{
...
}
- (void)clearFormTextFields
{
...
}
@end- Method declarations should always have a space after the class vs instance indicator (
-/+).
Example
+ (void)registerForPushNotifications;
- (void)clearDefaultRequestParameters;-
All Objective-C primitive types should be used over their C counterpart where available - this aids in future proofing code.
-
NSIntegerandNSUIntegershould be used over int, the only exception is for loop indices.
for (int i = 0; i < 10; i++) {
...
}-
CGFloatshould be used over float. -
The auxiliary and additional types such as
NSTimeIntervalshould be used (where relevant) over doubles.
- Variable names should always be camel cased with the first letter lowercase and the pointer prefixing the variable name.
Example
NSString *firstName;
NSString *lastName;- Variables should be named verbosely in line with Apple’s conventions. *The only exception is for loop indices.
Example
UIColor *configuredColorForView;- When declaring
IBOutletthe variable name should also be suffixed with the control type - this avoids issues with ambiguity when referencing the object later.
Example
self.usernameTextField.text = @"Chuck Norris";
[self.loginFormScrollView setContentOffset:aPoint animated:YES];- Use appropriate prefixes when working with
typedefstructures
Example
typedef enum {
BRTLoginStyleLight,
BRTLoginStyleDark
} BRTLoginStyle;- All View Controllers class names should be suffixed with ViewController.
Example
LoginViewController.m
RegisterViewController.m- Class factory methods should be created where relevant, in-line with Apple’s recommendation and best practices. This aids and simplifies the process of object creation by the client.
Example
+ (id)dateWithTimeIntervalSinceNow:(NSTimeInterval)secs;
+ (id)userWithFirstName:(NSString *)firstName lastName:(NSString *)lastName; - When invoking multiple methods on a single object limit to a maximum of 2 for readability and make sure there’s a space between each call.
Example
[DataManager sharedInstance] fetchFriends];-
Avoid declaring instance variables and opt for properties instead.
-
Dot-notation should be used to access and mutate properties.
Example
user.firstName = @”John”;
[DataManager sharedInstance].clientId;- Nonatomic first, for consistency.
Example
@property (nonatomic, strong) MPHostServiceBrowser *serviceBrowser;
@property (nonatomic, strong) NSMutableArray *connectionList;- If values need to be set on a
readonlyproperty declared in a header file declare the property with thereadwriteattribute in the .m file.
Example
@property (nonatomic, strong, readwrite) NSString *userId;-
Collection literals should always be used for non mutable items such as
NSArray,NSDictionaryetc. -
Access collection literals using the short syntax and the mutable counterpart using the family of
objectAtIndexmethods. This makes it clear what type of collection is being accessed.
Example
NSString *user = self.userList[0];
NSString *user = [self.userList objectAtIndex:0];- When working with large dictionaries (e.g. JSON responses) opt to create class representations (models) of the data instead, this will help with code completion and compiler checks and avoid any keyName mistakes.
- When defining
delegatecallbacks the format should be in line with the standard UIKit conventions which starts with the object responsible for the delegation, the auxiliary verb (will/should/did/has/should) and the event.
Example
scrollViewDidScroll:
webView:shouldStartLoadWithRequest:navigationType:Delegate/Data Sourcescan be declared in either code orInterface Builder, however the approach which is taken should be used consistently throughout the lifetime of theViewControllerto avoid a mix and match of the two, which leads to confusion when debugging. For example if anIBOutlethas itsdelegatedeclared inInterface Builderthen all other relevant objects should have theirdelegatesset inInterface Buildertoo.Interface Builderobjects which have theirdelegatedeclared in code should have these bundled together in an associated “setup” method.
- For apps across regions use NSLocalized string for all user displayed string output. You may optionally choose to use them in non-regional if also required because of the flexibility it provides.
Example
textField.placeholder = NSLocalizedString(@"Username", "Username Placeholder");- Opt to declare constants in
.h&.mfiles asstaticconstants and not#define– this should also include a header reference where relevant.
Example
// .h
extern NSString * const BRTRootUrl;
// .m
static NSString * const BRTRootUrl = @"http://www.boldrocket.com/"; - For common initializers always use a method named
commonInit, this should be used consistently across all relevant classes within the project.
Example
- (void)commonInit
{
// Common init code here!
}
- (instancetype)initWithFrame:(CGRect)aRect
{
if ((self = [super initWithFrame:aRect])) {
[self commonInit];
}
return self;
}
- (instancetype)initWithCoder:(NSCoder*)coder
{
if ((self = [super initWithCoder:coder])) {
[self commonInit];
}
return self;
}- If preference permits opt to use an
if/elsestatement over a ternary operator, the syntax is more explicit and in-line with Objective-C's more verbose syntax. If the ternary operator is used it should be kept to a maximum of 2 conditions.
Example
BOOL isUserActive = YES;
result = isUserActive ? valueIfTrue : valueIfFalse;While endeavouring to produce an initial version of the style guide it’s fully expected this will be require further revisions going forward, below highlighted is discussion points for potential inclusion at a future date.
- CGRect functions vs direct CGRect access