- Notifications
You must be signed in to change notification settings - Fork4
wantedly-archive/objective-c-style-guide
Folders and files
| Name | Name | Last commit message | Last commit date | |
|---|---|---|---|---|
Repository files navigation
This style guide outlines the coding conventions for wantedly.com.
This style guide outlines the coding conventions of the iOS team at The Wantedly. We welcome your feedback inissues,pull requests andtweets. Also,we're hiring.
- Dot-Notation Syntax
- Code Organization
- Spacing
- Conditionals
- Error handling
- Methods
- Variables
- Naming
- Comments
- Init & Dealloc
- Literals
- CGRect Functions
- Constants
- Case Statements
- Enumerated Types
- Private Properties
- Image Naming
- Booleans
- Singletons
- Golden Path
- Line Breaks
- Storyboard
- Category
- Directory
- Cocoapods
- Xcode Project
Dot-notation shouldalways be used for accessing and mutating properties. Bracket notation is preferred in all other instances.
For example:
view.backgroundColor = [UIColororangeColor];[UIApplicationsharedApplication].delegate;
Not:
[viewsetBackgroundColor:[UIColororangeColor]];UIApplication.sharedApplication.delegate;
Use#pragma mark - to categorize methods in functional groupings and protocol/delegate implementations following this general structure.
#pragma mark - Lifecycle- (instancetype)init {}- (void)dealloc {}- (void)viewDidLoad {}- (void)viewWillAppear:(BOOL)animated {}- (void)didReceiveMemoryWarning {}#pragma mark - Custom Accessors- (void)setCustomProperty:(id)value {}- (id)customProperty {}#pragma mark - IBActions- (IBAction)submitData:(id)sender {}#pragma mark - Public- (void)publicMethod {}#pragma mark - Private- (void)privateMethod {}#pragma mark - Protocol conformance#pragma mark - UITextFieldDelegate#pragma mark - UITableViewDataSource#pragma mark - UITableViewDelegate#pragma mark - NSCopying- (id)copyWithZone:(NSZone *)zone {}#pragma mark - NSObject- (NSString *)description {}
- Indent using 4 spaces. Never indent with tabs. Be sure to set this preference in Xcode.
- Method braces and other braces (
if/else/switch/whileetc.) 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}
- There should be exactly one blank line between methods to aid in visual clarity and organization. Whitespace within methods should separate functionality, but often there should probably be new methods.
@synthesizeand@dynamicshould 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 preventerrors. These errors include adding a second line and expecting it to be part of the if-statement. Another,even more dangerous defect may happen where the line "inside" the if-statement is commented out, and the next line unwittingly becomes part of the if-statement. In addition, this style is more consistent with all other conditionals, and therefore more easily scannable.
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. Evaluating multiple conditions is usually more understandable as an if statement, or refactored into instance variables.
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 (![selftrySomethingWithError:&error]) {// Handle Error}
Not:
NSError *error;[selftrySomethingWithError:&error];if (error) {// Handle Error}
Some of Apple’s APIs write garbage values to the error parameter (if non-NULL) in successful cases, so switching on the error can cause false negatives (and subsequently crash).
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;
Variables should be named as descriptively as possible. Single letter variable names should be avoided except infor() loops.
Asterisks indicating pointers belong with the variable, e.g.,NSString *text notNSString* text orNSString * 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 more information on using Accessor Methods in Initializer Methods and dealloc, seehere.
For example:
@interfaceNYTSection:NSObject@property (nonatomic)NSString *headline;@end
Not:
@interfaceNYTSection :NSObject {NSString *headline;}
Apple naming conventions should be adhered to wherever possible, especially those related tomemory management rules (NARC).
Long, descriptive method and variable names are good.
For example:
UIButton *settingsButton;
Not
UIButton *setBut;
A three letter prefix (e.g.NYT) should always be used for class names and constants, however may be omitted for Core Data entity names. Constants should be camel-case with all words capitalized and prefixed by the related class name for clarity.
For example:
staticconstNSTimeInterval NYTArticleViewControllerNavigationFadeAnimationDuration =0.3;
Not:
staticconstNSTimeInterval fadetime =1.7;
Properties and local variables should be camel-case with the leading word being lowercase.
Instance variables should be camel-case with the leading word being lowercase, and should be prefixed with an underscore. This is consistent with instance variables synthesized automatically by LLVM.If LLVM can synthesize the variable automatically, then let it.
For example:
@synthesize descriptiveVariableName = _descriptiveVariableName;
Not:
id varnm;When using properties, instance variables should always be accessed and mutated usingself.. This means that all properties will be visually distinct, as they will all be prefaced withself..
An exception to this: inside initializers, the backing instance variable (i.e. _variableName) should be used directly to avoid any potential side effects of the getters/setters.
Local variables should not contain underscores.
When they are needed, comments should be used to explainwhy a particular piece of code does something. Any comments that are used must be kept up-to-date or deleted.
Block comments should generally be avoided, as code should be as self-documenting as possible, with only the need for intermittent, few-line explanations. This does not apply to those comments used to generate documentation.
dealloc methods should be placed at the top of the implementation, directly after the@synthesize and@dynamic statements.init should be placed directly below thedealloc methods of any class.
init methods should be structured like this:
- (instancetype)init { self = [superinit];// or call the designated initalizerif (self) {// Custom initialization }return self;}
NSString,NSDictionary,NSArray, andNSNumber literals should be used whenever creating immutable instances of those objects. Pay special care thatnil values not be passed intoNSArray andNSDictionary literals, as this will cause a crash.
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 = [NSArrayarrayWithObjects:@"Brian",@"Matt",@"Chris",@"Alex",@"Steve",@"Paul",nil];NSDictionary *productManagers = [NSDictionarydictionaryWithObjectsAndKeys:@"Kate",@"iPhone",@"Kamal",@"iPad",@"Bill",@"Mobile Web",nil];NSNumber *shouldUseLiterals = [NSNumbernumberWithBool:YES];NSNumber *buildingZIPCode = [NSNumbernumberWithInteger:10018];
When accessing thex,y,width, orheight of aCGRect, always use theCGGeometry functions instead of direct struct member access. From Apple'sCGGeometry reference:
All functions described in this reference that take CGRect data structures as inputs implicitly standardize those rectangles before calculating their results. For this reason, your applications should avoid directly reading and writing the data stored in the CGRect data structure. Instead, use the functions described here to manipulate rectangles and to retrieve their characteristics.
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 are preferred over in-line string literals or numbers, as they allow for easy reproduction of commonly used variables and can be quickly changed without the need for find and replace. Constants should be declared asstatic constants and not#defines unless explicitly being used as a macro.
For example:
staticNSString *const NYTAboutViewControllerCompanyName =@"The New York Times Company";staticconst CGFloat NYTImageThumbnailHeight =50.0;
Not:
#defineCompanyName@"The New York Times Company"#definethumbnailHeight2
When usingenums, it is recommended to use the new fixed underlying type specification because it has stronger type checking and code completion. The SDK now includes a macro to facilitate and encourage use of fixed underlying types:NS_ENUM()
For Example:
typedefNS_ENUM(NSInteger, RWTLeftMenuTopItemType) { RWTLeftMenuTopItemMain, RWTLeftMenuTopItemShows, RWTLeftMenuTopItemSchedule};
You can also make explicit value assignments (showing older k-style constant definition):
typedefNS_ENUM(NSInteger, RWTGlobalConstants) { RWTPinSizeMin =1, RWTPinSizeMax =5, RWTPinCountMin =100, RWTPinCountMax =500,};
Older k-style constant definitions should beavoided unless writing CoreFoundation C code (unlikely).
Not Preferred:
enum GlobalConstants {kMaxPinSize =5,kMaxPinCount =500,};
Braces are not required for case statements, unless enforced by the complier.
When a case contains more than one line, braces should be added.
switch (condition) {case1:// ...break;case2: {// ...// Multi-line example using bracesbreak; }case3:// ...break;default:// ...break;}
There are times when the same code can be used for multiple cases, and a fall-through should be used. A fall-through is the removal of the 'break' statement for a case thus allowing the flow of execution to pass to the next case value. A fall-through should be commented for coding clarity.
switch (condition) {case1:// ** fall-through! **case2:// code executed for values 1 and 2break;default:// ...break;}
When using an enumerated type for a switch, 'default' is not needed. For example:
RWTLeftMenuTopItemType menuType = RWTLeftMenuTopItemMain;switch (menuType) {case RWTLeftMenuTopItemMain:// ...break;case RWTLeftMenuTopItemShows:// ...break;case RWTLeftMenuTopItemSchedule:// ...break;}
Private properties should be declared in class extensions (anonymous categories) in the implementation file of a class. Named categories (such asNYTPrivate orprivate) should never be used unless extending another class.
For example:
@interfaceNYTAdvertisement ()@property (nonatomic,strong) GADBannerView *googleAdView;@property (nonatomic,strong) ADBannerView *iAdView;@property (nonatomic,strong) UIWebView *adXWebView;@end
Image names should be named consistently to preserve organization and developer sanity. They should be named as one camel case string with a description of their purpose, followed by the un-prefixed name of the class or property they are customizing (if there is one), followed by a further description of color and/or placement, and finally their state.
For example:
RefreshBarButtonItem/RefreshBarButtonItem@2xandRefreshBarButtonItemSelected/RefreshBarButtonItemSelected@2xArticleNavigationBarWhite/ArticleNavigationBarWhite@2xandArticleNavigationBarBlackSelected/ArticleNavigationBarBlackSelected@2x.
Images that are used for a similar purpose should be grouped in respective groups in an Images folder.
Sincenil resolves toNO it is unnecessary to compare it in conditions. Never compare something directly toYES, becauseYES is defined to 1 and aBOOL 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 aBOOL, here are two examples:
if (isAwesome)if (![someObjectboolValue])
Not:
if ([someObjectboolValue] ==NO)if (isAwesome ==YES)// Never do this.
If the name of aBOOL 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;Text and example taken from theCocoa Naming Guidelines.
Singleton objects should use a thread-safe pattern for creating their shared instance.
+ (instancetype)sharedInstance {staticid sharedInstance =nil;staticdispatch_once_t onceToken;dispatch_once(&onceToken, ^{ sharedInstance = [[selfalloc]init]; });return sharedInstance;}
This will preventpossible and sometimes prolific crashes.
When coding with conditionals, the left hand margin of the code should be the "golden" or "happy" path. That is, don't nestif statements. Multiple return statements are OK.
Preferred:
- (void)someMethod {if (![someOtherboolValue]) {return; }//Do something important}
Not Preferred:
- (void)someMethod {if ([someOtherboolValue]) {//Do something important }}
Line breaks are an important topic since this style guide is focused for print and online readability.
For example:
self.productsRequest = [[SKProductsRequestalloc]initWithProductIdentifiers:productIdentifiers];
A long line of code like this should be carried on to the second line adhering to this style guide's Spacing section (two spaces).
self.productsRequest = [[SKProductsRequestalloc]initWithProductIdentifiers:productIdentifiers];
- UIColor is defined as category.
- Use Storyboard and autolayout.
- Storyboards should define user interfaces, not functionality.
- View ID and Segue ID is defined in WTDConstants.
//StoryboardIdentifier#define kTermsStoryboardIdentifier @"Terms"//Segue#define kPushProjectSegue @"PushProject"#define kEmbedProjectsSegue @"EmbedProjects"- Extensions is defined by the category.
.+-- Classes| +-- WTDAppDelegate.h| +-- WTDAppDelegate.m| +-- WTDConstants.m| +-- Extensions| +-- Controllers| +-- Models| +-- Views+-- Resources| +-- Stylesheets| +-- Storyboards| +-- IB Files| +-- Locales| +-- Images.xcassets+-- Supporting Files- Use cocoapods as much as possible.
- Use these libraries instead of reinventing the wheel:
- RestKit - consuming and modeling RESTful web resources
- AFNetworking - networking framework
- SDWebImage - Asynchronous image downloader with cache support with an UIImageView category
- RNCryptor - Encryptor/Decryptor
- UICKeyChainStore - a simple wrapper for Keychain
- SVProgressHUD - A clean and lightweight progress HUD
- TTTAttributedLabel - A drop-in replacement for UILabel that supports attributes, data detectors, links, and more.
- NUI - Style iOS apps with a stylesheet, similar to CSS
- JLRoutes - Advanced URL parsing designed to handle complex URL schemes with a block-based callback API
- site for searching popular cocoapodshttp://cocoapods.wantedly.com/
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 manyadditional warnings as possible. If you need to ignore a specific warning, useClang's pragma feature.
About
Resources
Uh oh!
There was an error while loading.Please reload this page.
Stars
Watchers
Forks
Releases
Packages0
Contributors2
Uh oh!
There was an error while loading.Please reload this page.