從其他地方整理了一些編碼規(guī)范的資料,分享給大家。YoY
1.語言(Language)
需要使用US English
US English should be used.
Preferred:
UIColor *myColor = [UIColor whiteColor];
Not Preferred:
UIColor *myColour = [UIColor whiteColor];
代碼組織(Code Organization)
使用 #pragma mark 將方法按照功能以及協(xié)議/委托實現(xiàn)進行組織,參考下面的通用結(jié)構(gòu)范本。
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 {}
2.空白(Spacing)
? 縮進是用2個空格(這種方式節(jié)省空間,并盡可能減少換行),不要使用tab縮進,確保已在Xcode里面設(shè)定好相關(guān)偏好設(shè)置
Indent using 2 spaces (this conserves space in print and makes line wrapping less likely). Never indent with tabs. Be sure to set this preference in Xcode.
? 方法和其他代碼(if/else/switch/while等等)的大括號總是在一行打開,在新行結(jié)束
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.
Preferred:
if (user.isHappy) {
//Do something
} else {
//Do something else
}
Not Preferred:
if (user.isHappy){
//Do something
}else {
//Do something else
}
? 為了方便閱讀以及代碼組織,需要在方法之間增加一個空行。方法內(nèi)的空行用于區(qū)分不同的功能代碼,但是如果方法中又太多的功能區(qū)塊那么需要考慮重構(gòu)代碼。
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.
? 最好使用auto-synthesis。但是,如果有必要,@synthesize和@dynamic應(yīng)各自在實現(xiàn)的新行定義。
Prefer using auto-synthesis. But if necessary, @synthesize and @dynamic should each be declared on new lines in the implementation.
? 通常不要使用冒號(:)對齊方法調(diào)用。但是有些情況下一個方法簽名可能有>=3個冒號,使用冒號對齊可以使代碼更易讀。請不要使用冒號對齊含實現(xiàn)塊的方法,因為Xcode的縮進會使代碼更難讀。
Colon-aligning method invocation should often be avoided. There are cases where a method signature may have >= 3 colons and colon-aligning makes the code more readable. Please do NOT however colon align methods containing blocks because Xcode's indenting makes it illegible.
Preferred:
// blocks are easily readable
[UIView animateWithDuration:1.0 animations:^{
// something
} completion:^(BOOL finished) {
// something
}];
Not Preferred:
// colon-aligning makes the block indentation hard to read
[UIView animateWithDuration:1.0
animations:^{
// something
}
completion:^(BOOL finished) {
// something
}];
3.注釋(Comments)
當需要注釋時,注釋需要描述一段代碼的功能。所有注釋需要保持更新,不需要的注釋需要刪除。
When they are needed, comments should be used to explain why 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.
例外情況:這個規(guī)則不適用于為生成文檔而編寫的注釋。
Exception: This does not apply to those comments used to generate documentation.
4.命名(Naming)
應(yīng)該遵守Apple的命名規(guī)則,尤其涉及到內(nèi)存管理規(guī)則部分的命名規(guī)則。
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.
Preferred:
UIButton *settingsButton;
Not Preferred:
UIButton *setBut;
類名和常量名需要有三個字符的前綴,對于核心數(shù)據(jù)的實體類則可以神略。
A three letter prefix should always be used for class names and constants, however may be omitted for Core Data entity names. For any official raywenderlich.com books, starter kits, or tutorials, the prefix 'RWT' should be used.
常量應(yīng)該使用駝峰格式(首字母大寫)命名并且增加相關(guān)類的前綴。
Constants should be camel-case with all words capitalized and prefixed by the related class name for clarity.
Preferred:
static NSTimeInterval const RWTTutorialViewControllerNavigationFadeAnimationDuration = 0.3;
Not Preferred:
static NSTimeInterval const fadetime = 1.7;
屬性應(yīng)該使用駝峰格式命名(第一個字母小寫)。為屬性使用auto-synthesis,不要手工增加@synthesiz語句(除非你有更好的理由)。
Properties should be camel-case with the leading word being lowercase. Use auto-synthesis for properties rather than manual @synthesize statements unless you have good reason.
Preferred:
@property (strong, nonatomic) NSString *descriptiveVariableName;
Not Preferred:
id varnm;
5.下劃線(Underscores)
當使用屬性,實例變量時應(yīng)該使用self.來訪問,這意味著所有的屬性將很容易區(qū)分,因為它們都使用 self. 開頭。
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..
一個例外:在初始化代碼中的backing instance variable(如:_variableName)應(yīng)直接使用,避免getter/setter方法中的任何潛在的問題。
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.
局部變量不應(yīng)該包含下劃線。
Local variables should not contain underscores.
6.方法(Methods)
在方法簽名中需要在方法類型(-/+符號)后面增加一個空格。需要在方法段之間增加空白(符合蘋果樣式)。需包含關(guān)鍵字并且關(guān)鍵字需要能描述參數(shù)。關(guān)鍵字 and 是保留的,不要在多個參數(shù)中(如下面initWithWidth:height)所示使用and。
In method signatures, there should be a space after the method type (-/+ symbol). There should be a space between the method segments (matching Apple's style). Always include a keyword and be descriptive with the word before the argument which describes the argument.
The usage of the word "and" is reserved. It should not be used for multiple parameters as illustrated in the initWithWidth:height: example below.
Preferred:
- (void)setExampleText:(NSString *)text image:(UIImage *)image;
- (void)sendAction:(SEL)aSelector to:(id)anObject forAllCells:(BOOL)flag;
- (id)viewWithTag:(NSInteger)tag;
- (instancetype)initWithWidth:(CGFloat)width height:(CGFloat)height;
Not Preferred:
- (void)setT:(NSString *)text i:(UIImage *)image;
- (void)sendAction:(SEL)aSelector :(id)anObject :(BOOL)flag;
- (id)taggedView:(NSInteger)tag;
- (instancetype)initWithWidth:(CGFloat)width andHeight:(CGFloat)height;
- (instancetype)initWith:(int)width and:(int)height; // Never do this.
7.變量(Variables)
變量命名需要盡可能的有意義。不要單字符命名變量(除了for循環(huán)中)。*號代表指針應(yīng)該定義的靠近變量(常量例外),如:NSString text, 不要用NSString text 或者 NSString * text。
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.
Private properties should be used in place of instance variables whenever possible. Although using instance variables is a valid way of doing things, by agreeing to prefer properties our code will be more consistent.
Direct access to instance variables that 'back' properties 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, see here.
Preferred:
@interface RWTTutorial : NSObject
@property (strong, nonatomic) NSString *tutorialName;
@end
Not Preferred:
@interface RWTTutorial : NSObject {
NSString *tutorialName;
}
8.Property Attributes
Property屬性需要明確列出,這樣有助于其他程序員閱讀代碼。屬性順序應(yīng)該是storage然后是atomicity,這個順序與代碼生成器生成的代碼順序一致。
Property attributes should be explicitly listed, and will help new programmers when reading the code. The order of properties should be storage then atomicity, which is consistent with automatically generated code when connecting UI elements from Interface Builder.
Preferred:
@property (weak, nonatomic) IBOutlet UIView *containerView;
@property (strong, nonatomic) NSString *tutorialName;
Not Preferred:
@property (nonatomic, weak) IBOutlet UIView *containerView;
@property (nonatomic) NSString *tutorialName;
易變的屬性需要使用copy來代替strong。為什么?如果你聲明了一個NSString的屬性,另外一個人或許會將他放到NSMutableString的實例,這樣就會改變你原先的NSString。
Properties with mutable counterparts (e.g. NSString) should prefer copy instead of strong. Why? Even if you declared a property as NSString somebody might pass in an instance of an NSMutableString and then change it without you noticing that.
Preferred:
@property (copy, nonatomic) NSString *tutorialName;
Not Preferred:
@property (strong, nonatomic) NSString *tutorialName;
9.點標記語法(Dot-Notation Syntax)
點語發(fā)是使用訪問控制方法的易用包裝,當你使用點語法時,屬性的訪問和設(shè)置將會通過gettet和setter方法進行。
Dot syntax is purely a convenient wrapper around accessor method calls. When you use dot syntax, the property is still accessed or changed using getter and setter methods. Read more here
當訪問和修改屬性是應(yīng)該總是使用點語法,這會使得代碼更簡潔。括號符號具有更高的優(yōu)先級。
Dot-notation should always be used for accessing and mutating properties, as it makes code more concise. Bracket notation is preferred in all other instances.
Preferred:
NSInteger arrayCount = [self.array count];
view.backgroundColor = [UIColor orangeColor];
[UIApplication sharedApplication].delegate;
Not Preferred:
NSInteger arrayCount = self.array.count;
[view setBackgroundColor:[UIColor orangeColor]];
UIApplication.sharedApplication.delegate;
9.文字(Literals)
創(chuàng)建不易變類型實例是應(yīng)該使用NSString, NSDictionary, NSArray, and NSNumber。要特別小心,nil值不能被傳遞到的NSArray和NSDictionary中,因為這會導致崩潰。
NSString, NSDictionary, NSArray, and NSNumber literals should be used whenever creating immutable instances of those objects. Pay special care that nil values can not be passed into NSArray and NSDictionary literals, as this will cause a crash.
Preferred:
NSArray *names = @[@"Brian", @"Matt", @"Chris", @"Alex", @"Steve", @"Paul"];
NSDictionary *productManagers = @{@"iPhone": @"Kate", @"iPad": @"Kamal", @"Mobile Web": @"Bill"};
NSNumber *shouldUseLiterals = @YES;
NSNumber *buildingStreetNumber = @10018;
Not Preferred:
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 *buildingStreetNumber = [NSNumber numberWithInteger:10018];
10.常量(Constants)
常量優(yōu)于內(nèi)聯(lián)字符串文字或數(shù)字,因為它們允許容易地表示常用變量,并且可以被快速改變而無需查找和替換。除非明確地被用作宏(使用#defines定義),常量應(yīng)聲明為靜態(tài)的。
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 as static constants and not #defines unless explicitly being used as a macro.
Preferred:
static NSString * const RWTAboutViewControllerCompanyName = @"RayWenderlich.com";
static CGFloat const RWTImageThumbnailHeight = 50.0;
Not Preferred:
#define CompanyName @"RayWenderlich.com"
#define thumbnailHeight 2
11.枚舉類型(Enumerated Types)
當使用枚舉時,建議使用新的固定的基本類型規(guī)范,因為它具有更強的類型檢查和代碼完成。SDK現(xiàn)在包括一個宏來促進和鼓勵使用固定的基本類型: NS_ENUM()
When using enums, 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:
typedef NS_ENUM(NSInteger, RWTLeftMenuTopItemType) {
RWTLeftMenuTopItemMain,
RWTLeftMenuTopItemShows,
RWTLeftMenuTopItemSchedule
};
您也可以進行明確賦值(老式的k-style常量定義)
You can also make explicit value assignments (showing older k-style constant definition):
typedef NS_ENUM(NSInteger, RWTGlobalConstants) {
RWTPinSizeMin = 1,
RWTPinSizeMax = 5,
RWTPinCountMin = 100,
RWTPinCountMax = 500,
};
舊的k-style常量定義應(yīng)該避免使用除非你在編寫核心的C代碼。
Older k-style constant definitions should be avoided unless writing CoreFoundation C code (unlikely).
Not Preferred:
enum GlobalConstants {
kMaxPinSize = 5,
kMaxPinCount = 500,
};
12.Case語句(Case Statements)
case語句不要使用括號,除非編譯器提示。當case包含超過一行語句時,需要增加括號。
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) {
case 1:
// ...
break;
case 2: {
// ...
// Multi-line example using braces
break;
}
case 3:
// ...
break;
default:
// ...
break;
}
有些情況下,相同的代碼可以適用于多個case以及下方的case語句,可以去掉case后的break語句允許執(zhí)行下方case代碼,這種語句需要進行注釋來保證代碼的清晰。
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) {
case 1:
// ** fall-through! **
case 2:
// code executed for values 1 and 2
break;
default:
// ...
break;
}
在swithc中使用enum時,不需要default段
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;
}
13.私有屬性(Private Properties)
私有屬性應(yīng)該在類實現(xiàn)文件的擴展(匿名類)中聲明。命名類別(如RWTPrivate或private)不應(yīng)該被使用,除非擴展另一個類。匿名類可以共享/暴露使用+Private.h文件命名約定檢驗。
Private properties should be declared in class extensions (anonymous categories) in the implementation file of a class. Named categories (such as RWTPrivate or private) should never be used unless extending another class. The Anonymous category can be shared/exposed for testing using the +Private.h file naming convention.
For Example:
@interface RWTDetailViewController ()
@property (strong, nonatomic) GADBannerView *googleAdView;
@property (strong, nonatomic) ADBannerView *iAdView;
@property (strong, nonatomic) UIWebView *adXWebView;
@end
14.布爾值(Booleans)
Objective-C使用 YES 和 NO。因此 true 和 false 只能在用于CoreFoundation的 C 或 C++代碼中。因為nil被解析為NO所以nil不需要在條件中比較它。從不直接比較YES,因為YES是被定義為1,而一個布爾值可多達8位。
Objective-C uses YES and NO. Therefore true and false should only be used for CoreFoundation, C or C++ code. 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.
Preferred:
if (someObject) {}
if (![anotherObject boolValue]) {}
Not Preferred:
if (someObject == nil) {}
if ([anotherObject boolValue] == NO) {}
if (isAwesome == YES) {} // Never do this.
if (isAwesome == true) {} // Never do this.
如果BOOL屬性的名稱表示為一個形容詞,該屬性可以省略“is”字頭,但需要為get方法按照常規(guī)指定名稱,例如:
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;
Text and example taken from the Cocoa Naming Guidelines.
15.條件語句(Conditionals)
條件體應(yīng)當始終需要用括號以避免錯誤,即使條件體可以不用括號(比如僅一行的條件語句)。這些錯誤包括增加第二行代碼,并期待它是if語句的一部分。另一個更危險的缺陷可能發(fā)生的地方就行“內(nèi)部”的if語句被注釋掉,并使得下一行不知不覺成為if語句的一部分。此外,這種風格是與所有其他條件句更一致的,因此更容易可掃描。
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. 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.
Preferred:
if (!error) {
return success;
}
Not Preferred:
if (!error)
return success;
or
if (!error) return success;
16.三元運算符(Ternary Operator)
僅僅當為了提高代碼可讀性和整潔性的時候才可以使用三元運算符,通常是一個單一的條件。多個條件通常使用更易于理解的if語句或重構(gòu)到實例變量。在一般情況下,三元運算的最佳使用場景是根據(jù)條件為變量賦值。
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. In general, the best use of the ternary operator is during assignment of a variable and deciding which value to use.
布爾變量比較時應(yīng)該使用否 != 比較需要增加括號,以提高可讀性。如果變量是一個布爾類型,那么沒有必要添加括號。
Non-boolean variables should be compared against something, and parentheses are added for improved readability. If the variable being compared is a boolean type, then no parentheses are needed.
Preferred:
NSInteger value = 5;
result = (value != 0) ? x : y;
BOOL isHorizontal = YES;
result = isHorizontal ? x : y;
Not Preferred:
result = a > b ? x = c > d ? c : d : y;
17.初始化方法(Init Methods)
初始化方法依照Apple的通用代碼模板即可。返回類型為instancetpye時應(yīng)該使用返回id。
Init methods should follow the convention provided by Apple's generated code template. A return type of 'instancetype' should also be used instead of 'id'.
- (instancetype)init {
self = [super init];
if (self) {
// ...
}
return self;
}
See Class Constructor Methods for link to article on instancetype.
類構(gòu)造器方法(Class Constructor Methods)
當類構(gòu)造器方法被調(diào)用后,返回instancetype類型不要返回id。這確保編譯器能夠正確推斷結(jié)果類型。
Where class constructor methods are used, these should always return type of 'instancetype' and never 'id'. This ensures the compiler correctly infers the result type.
@interface Airplane
+ (instancetype)airplaneWithType:(RWTAirplaneType)type;
@end
More information on instancetype can be found on NSHipster.com.
18.CGRect函數(shù)(CGRect Functions)
當訪問CGRect的x,y,width,height屬性時,需要使用CGGeometry 函數(shù) 而不要直接訪問結(jié)構(gòu)成員。參考apple 的CGGeometry參考:
When accessing the x, y, width, or height of a CGRect, always use the CGGeometry functions instead of direct struct member access. From Apple's CGGeometry 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.
Preferred:
CGRect frame = self.view.frame;
CGFloat x = CGRectGetMinX(frame);
CGFloat y = CGRectGetMinY(frame);
CGFloat width = CGRectGetWidth(frame);
CGFloat height = CGRectGetHeight(frame);
CGRect frame = CGRectMake(0.0, 0.0, width, height);
Not Preferred:
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;
CGRect frame = (CGRect){ .origin = CGPointZero, .size = frame.size };
Golden Path
當編寫條件語句代碼,不能嵌套if語句。多個return語句都OK。
When coding with conditionals, the left hand margin of the code should be the "golden" or "happy" path. That is, don't nest if statements. Multiple return statements are OK.
Preferred:
- (void)someMethod {
if (![someOther boolValue]) {
return;
}
//Do something important
}
Not Preferred:
- (void)someMethod {
if ([someOther boolValue]) {
//Do something important
}
}
19.錯誤處理(Error handling)
When methods return an error parameter by reference, switch on the returned value, not the error variable.
Preferred:
NSError *error;
if (![self trySomethingWithError:&error]) {
// Handle Error
}
Not Preferred:
NSError *error;
[self trySomethingWithError:&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).
20.Singletons
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.
21.Line Breaks
Line breaks are an important topic since this style guide is focused for print and online readability.
For example:
self.productsRequest = [[SKProductsRequest alloc] 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 = [[SKProductsRequest alloc] initWithProductIdentifiers:productIdentifiers];
Smiley Face
Smiley faces are a very prominent style feature of the raywenderlich.com site! It is very important to have the correct smile signifying the immense amount of happiness and excitement for the coding topic. The end square bracket is used because it represents the largest smile able to be captured using ascii art. A half-hearted smile is represented if an end parenthesis is used, and thus not preferred.
Preferred:
:]
Not Preferred:
:)
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.
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.