Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Our code style guidelines

License

NotificationsYou must be signed in to change notification settings

macoscope/objc-style-guide

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

6 Commits
 
 
 
 

Repository files navigation

This style guide describes a set of basic rules that we follow here atMacoscope. We strive to write better code every day, and we believe this document outlines the best practices that will help you do the same.

This document is based on, and inspired by, the awesomeNYTimes Objective-C Style Guide.

Also,we're hiring.

Mandatory Reading

If you haven't read theCoding Guidelines for Cocoa yet, it's probably a good idea to stop right here and come back only after you're finished with it. You should pay special attention to:

Table of Contents

Dot-Notation Syntax

Property? Dot-notation.Always.

Not a property? Brackets.

If Apple brings their frameworks up to date with modern ObjC syntax, feel free to use dot-notation when targeting earlier releases.

For example:

array.count;[UIApplicationsharedApplication].delegate;

Not:

[arraycount];UIApplication.sharedApplication.delegate;

Spacing

  • 4 spaces. Soft tabs. Period.
    • When working with older projects that usedwrong number of spaces, adapt to the existing style.Do not convert existing projects to new guidelines or you'll breakgit blame.
  • 1TBS for control statements.
  • K&R for method declaration. (Opening brace appears in the following line.)
  • Never omit braces in control statements,goto fail; should be a convincing enough argument for everyone.

For example:

- (void)describeCodingStyleWithCodingStyle:(MCSCodingStyle)style{if (MCSCodingStyleKAndR == style) {        [selfdoSomething];    }}
  • Separate methods withone empty line. Use whitespace in methods as needed, but if you find yourself separating multiple groups of statements, there's a good chance they should be split into separate methods.

Ternary Operator

If you're writing (or, for that matter, reading) multiple nested ternary operators, it means that something, somewhere went wrong. Write it in a different way (if statement, instance variable) and refactor existing occurrences.

For example:

goodThing = a > b ? x : y;

Not:

badThing = a > b ? x = c > d ? c : d : y;

Error handling

If you haven't already, you should probably read @mattt'sexcellent write-up ofNSError onNSHipster.

TL;DR version: Check for returned value, not error variable.

For example:

NSError *error;if (![selfmagicalOperationThatCanResultInError:&error]) {// whoops. Better handle this!}

Not:

NSError *error;[selfmagicalOperationThatCanResultInError:&error];if (error) {// whoops. Better handle this!}

But really, read that NSHipster article.

Methods

Follow Apple API examples and docs. A space between+/- and method name, a space between method segments, a space between type and asterisk. No spaces anywhere else.

For example:

- (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath;

Not:

- (BOOL) tableView: (UITableView *) tableView canMoveRowAtIndexPath: (NSIndexPath *) indexPath;

Multiargument methods like new lines between arguments, colon-aligned.

For example:

- (void)thisViewController:(ThisViewController *)thisViewController        didFinishWithThing:(Thing *)thing             somethingElse:(SomethingElse *)somethingElse                     style:(Style)style;- (void)prepareCakeWithIngredients:(NSArray *)ingredients                           success:(void(^)(Cake *deliciousCake))success                           failure:(void(^)(NSError *))failure;

Variables

Make things as simple as possible, but not simpler.

If you're unsure which side you fall on, it's better to err on the side of wordiness.

There shouldn't be any reason to use one-letter variable names apart fromfor() loops.

Asterisks hug the variable name, not the type.

For example:

NSString *macoscopeString;

Not:

NSString* macoscopeString;

Use properties over naked instance variables.

Generally avoid directly accessing instance variables, except in initializer methods (init,initWithCoder:, etc…),dealloc methods and within custom setters and getters. SeeAdvanced Memory Management Programming Guide for rationale.

For example:

@interfaceMCSObject:NSObject@property (nonatomic,strong)NSString *title;@end

Not:

@interfaceMCSObject :NSObject {NSString *title;}

Variable Qualifiers

When it comes to the variable qualifiersintroduced with ARC, the qualifier (__strong,__weak,__unsafe_unretained,__autoreleasing) should be placed first, e.g.,__weak NSString *text. This is technically incorrect, but much more clear since it immediately stands out (and is allowed by the compiler).

Property attributes

Property attributes are declared in the following order:

  1. Atomicity (nonatomic)
  2. Storage type (weak,strong,copy, etc.)
  3. Visibility (readonly,readwrite)
  4. Custom getters and setters

For example:

@property (nonatomic, strong, readonly)NSManagedObjectContext *managedObjectContext;@property (nonatomic, weak)IBOutlet UILabel *detailDescriptionLabel;@property (nonatomic)BOOL selected;

Naming

Apple’s naming conventions should be adhered to wherever possible, especially those related tomemory management rules (NARC).

For example:

UIButton *magicButton;

Not:

UIButton *magBut;

Use MCS prefixes for internal code. Three-letter class prefixes are preferred, but Apple doesn't respect their own guidelines in this regard anyway (seeMantle andMetal). You can omit them for Core Data entity names.

Externally visible constants should be written in camel case with all words capitalized and prefixed by the related class name for clarity.

For example:

// MCSMagicalCollectionView.hexternNSString *const MCSMagicalCollectionViewDidSparkleNotification;

Not:

staticconstNSTimeInterval animDuration =0.5;

Properties and local variables should be in camel case with the leading word being lowercase.

Instance variables should be in 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;

Comments

Use common sense. Explain why you’re doing something, not the steps you’re taking.

Never commit code that has been commented out (take a second and go throughgit diff before applying your changes, make sure you're leaving codebase in better shape than before, no one likes to deal with a messy code).

Documentation comments are good. Use them when they're actually useful and needed. If you can refactor something so that you don't need to explain it, do that instead.

Init and Dealloc

init methods go at the top.dealloc goes right below them. Consider wrapping them in#pragma mark - Lifecycle or something similar.

init methods should be structured like this:

- (instancetype)init{    self = [superinit];// or call the designated initializerif (self) {// Custom initialization    }return self;}

Where applicable,always returninstancetype.

Literals

Then Apple said, "I give youNSDictionary,NSArray,NSString, andNSNumber literals." And Apple saw everything it had made, and behold, it was very good.

No, really. They're good for you. Use them.

For example:

NSArray *names = @[@"Agata",@"Ania",@"Bartek",@"Daniel",@"Dawid",@"Dominik",@"Jarek",@"Karol",@"Klaudia",@"Maciej",@"Maciej",@"Marcin",@"Rafał",@"Wojtek",@"Wojtek",@"Zbigniew",@"Janek"];NSDictionary *animals = @{@"dogs" : @[@"Boomer"]};NSNumber *officeIndoorSwimmingPool = @YES;NSNumber *over9000 = @9001;

Categories

Categories should be declared in separate files called ClassName+CategoryName.{h,m}.

There are no well-defined semantics for defining the same method in more than one category. In order to avoid undefined behavior, add a prefix to method names in categories on framework classes (e.g.NSArray,UIImageView,AFHTTPRequestOperationManager). Don't add a prefix to method names in categories on your own classes.

For example:

// NSArray+MCSCollectionUtility.h@interfaceNSArray (MCSCollectionUtility)- (void)mcs_each:(void(^)(id object))block;- (void)mcs_eachWithIndex:(void(^)(id object,NSUInteger index))block;...
// MCSMagicalCollectionView+AbraCadabra.h@interfaceMCSMagicalCollectionView (AbraCadabra)- (void)abraCadabra;- (void)hocusPocus;...

CGRect Functions

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;

In most common scenarios, when you want to get the size of a view, refer to itsbounds and notframe. You can readthis post to know why it might not be safe to base off offrame.

CGRect bounds = self.view.bounds;CGFloat width = CGRectGetWidth(bounds);CGFloat height = CGRectGetHeight(bounds);

Try not to cut corners when you're adding a view which fills the entire superview.UIScrollView changesbounds when changingcontentOffset.

CGRect superBounds = self.view.bounds;UIView *subview = [[UIViewalloc]initWithFrame:CGRect(0,0,CGRectGetWidth(superBounds),CGRectGetHeight(superBounds)];

Instead of:

CGRect superBounds = self.view.bounds;UIView *subview = [[UIViewalloc]initWithFrame:superBounds];

Remember aboutconvertRect:toView: andconvertRect:fromView: methods when working with frames. They also handle theUIScollViewbounds well.

CGRect frameWithoutTransformations = [scrollViewconvertRect:scrollView.boundstoView:scrollView.superview];

Constants

Magic values should be avoided. If you do need to define a constant, it should be astatic constant.

Avoid#defines. Unless you're writing an actual macro. Then, by all means, go ahead.

You may use Hungarian notation for implementation-level constants.

For example:

// MCSCompany.hexternNSString *const MCSCompanyTagline;// MCSCompany.mNSString *const MCSCompanyTagline =@"We make award-winning apps for Apple devices.";staticNSString *constkOfficeLocation =@"Warsaw, Poland";

Not:

#defineCompanyTagline@"We make award-winning apps for Apple devices."#definemaxNumberOfRows2

Enumerated Types

Use NS_ENUM(). Not sure why? NSHipsterhas you covered.

NS_ENUM also providesSwift interoperability.

For example:

// MCSFishEye.htypedefNS_ENUM(NSInteger, MCSFishEyeState) {    MCSFishEyeStateCollapsed,    MCSFishEyeStateExpandedActive,    MCSFishEyeStateExpandedPassive};
// SomeFile.swiftfishEyeView.state=.Collapsed

Bitmasks

NS_OPTIONS(). For the same reasons as stated earlier with regards to NS_ENUM(). Again, read the article.

For example:

typedefNS_OPTIONS(NSUInteger, MCSCustomerHappiness) {    MCSCustomerHappinessVeryHapy =1 <<0,    MCSCustomerHappinessExtremelyHappy =1 <<1,    MCSCustomerHappinessEnormouslyHappy =1 <<2};

Private Properties

Private properties should be declared in class extensions (anonymous categories) in the implementation file of a class. Named categories (such asMCSPrivate orprivate) should never be used unless you’re extending another class.

For example:

@interfaceMCSFishEyeView()@property (nonatomic,strong)NSArray *itemContainers;@property (nonatomic,strong)NSArray *items;@property (nonatomic,strong) UIView *transformView;@end

Custom getters

There's no real consensus here. But remember, custom getters arecustom for a reason. In most cases, when you have a property, the default getter should work just fine. That's what most developers expect. They see a header file and expect the default behaviour.

If you want to lazy load somethings, to have a singleton object or to have areadonly property whose result has to be calculated (ex.count ofNSArray), feel free to create one. Just make sure you have a good reason to do so.

Subclassing and Testing

Private properties and methods that need to be visible to some parts of the code for subclassing or testing purposes should be declared in class extensions in separate header files. To indicate the private nature of the header, the filename should follow theClassName_Description.h format (notice an_ used instead of a+ to differentiate from category headers).

For example:

// MCSSomeObject_PrivateProperties.h@interfaceMCSSomeObject ()@property (nonatomic)NSInteger someProperty;@end
// MCSSomeObject.m#import"MCSSomeObject.h"#import"MCSSomeObject_PrivateProperties.h"

Booleans

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.

Singletons

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.

Try not to create excessive singletons. Perhaps what you're trying to do could be accomplished much easier using dependency injection?

Xcode Project

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. You can useSynx by @venmo to organize the files on your disk for you.

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.

Refactoring

When you add/change code and you see that the nearby code is bad (e.g. doesn't comply with the guidelines you're reading right now),change it.

Example: you want to add a constant at the top of a file and you see that already present constants use #define instead of const. First, in a separate commit, change #define to const, then add your constant.

Miscellaneous

  • Given how long Objective-C identifiers can get, it's rather pointless to enforce the hard line length limit. However, it's also important to not get carried away, so turn on page guide at column 100. Don't be afraid to break it when it increases code clarity.
  • Don't be afraid of multiple return statements. Your code should follow thegolden path. Multiple nested conditionals should be avoided.

Other Objective-C Style Guides

If ours doesn't fit your tastes, have a look at some other style guides:

Acknowledgements

This document is largely based on theNYTimes Objective-C Style Guide, with sections we agreed with and felt we couldn't improve upon pulled verbatim from it.

It's also heavily influenced by and referencesNSHipster in multiple places.

About

Our code style guidelines

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Contributors3

  •  
  •  
  •  

[8]ページ先頭

©2009-2025 Movatter.jp