├── .gitignore
├── LICENSE
└── README.md
/.gitignore:
--------------------------------------------------------------------------------
1 | # Xcode
2 | #
3 | build/
4 | *.pbxuser
5 | !default.pbxuser
6 | *.mode1v3
7 | !default.mode1v3
8 | *.mode2v3
9 | !default.mode2v3
10 | *.perspectivev3
11 | !default.perspectivev3
12 | xcuserdata
13 | *.xccheckout
14 | *.moved-aside
15 | DerivedData
16 | *.hmap
17 | *.ipa
18 | *.xcuserstate
19 |
20 | # CocoaPods
21 | #
22 | # We recommend against adding the Pods directory to your .gitignore. However
23 | # you should judge for yourself, the pros and cons are mentioned at:
24 | # http://guides.cocoapods.org/using/using-cocoapods.html#should-i-ignore-the-pods-directory-in-source-control
25 | #
26 | #Pods/
27 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2015 Sam Lau
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
23 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # raywenderlich.com Objective-C编码规范
2 |
3 | 这篇编码风格指南概括了raywenderlich.com的编码规范,可能有些删减或修改。
4 |
5 | ## 介绍
6 |
7 | 我们制定Objective-C编码规范的原因是我们能够在我们的书,教程和初学者工具包的代码保持优雅和一致。即使我们有很多不同的作者来完成不同的书籍。
8 |
9 |
10 | 这里编码规范有可能与你看到的其他Objective-C编码规范不同,因为它主要是为了打印和web的易读性。
11 |
12 | ## 关于作者
13 |
14 | 这编码规范的创建是由很多来自raywenderlich.com团队成员在Nicholas Waynik的带领下共同完成的。团队成员有:[Soheil Moayedi Azarpour](https://github.com/moayes), [Ricardo Rendon Cepeda](https://github.com/ricardo-rendoncepeda), [Tony Dahbura](https://github.com/tdahbura), [Colin Eberhardt](https://github.com/ColinEberhardt), [Matt Galloway](https://github.com/mattjgalloway), [Greg Heo](https://github.com/gregheo), [Matthijs Hollemans](https://github.com/hollance), [Christopher LaPollo](https://github.com/elephantronic), [Saul Mora](https://github.com/casademora), [Andy Pereira](https://github.com/macandyp), [Mic Pringle](https://github.com/micpringle), [Pietro Rea](https://github.com/pietrorea), [Cesare Rocchi](https://github.com/funkyboy), [Marin Todorov](https://github.com/icanzilb), [Nicholas Waynik](https://github.com/ndubbs)和[Ray Wenderlich](https://github.com/raywenderlich)
15 |
16 | 我们也非常感谢[New York Times](https://github.com/NYTimes/objective-c-style-guide) 和[Robots & Pencils'](https://github.com/RobotsAndPencils/objective-c-style-guide)Objective-C编码规范的作者。这两个编码规范为本指南的创建提供很好的起点。
17 |
18 | ## 背景
19 |
20 | 这里有些关于编码风格Apple官方文档,如果有些东西没有提及,可以在以下文档来查找更多细节:
21 |
22 | * [The Objective-C Programming Language](http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/ObjectiveC/Introduction/introObjectiveC.html)
23 | * [Cocoa Fundamentals Guide](https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/CocoaFundamentals/Introduction/Introduction.html)
24 | * [Coding Guidelines for Cocoa](https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/CodingGuidelines/CodingGuidelines.html)
25 | * [iOS App Programming Guide](http://developer.apple.com/library/ios/#documentation/iphone/conceptual/iphoneosprogrammingguide/Introduction/Introduction.html)
26 |
27 | ## 目录
28 |
29 | * [语言](#language)
30 | * [代码组织](#code-organization)
31 | * [空格](#spacing)
32 | * [注释](#comments)
33 | * [命名](#naming)
34 | * [下划线](#underscores)
35 | * [方法](#methods)
36 | * [变量](#variables)
37 | * [属性特性](#property-attributes)
38 | * [点符号语法](#dot-notation-syntax)
39 | * [字面值](#literals)
40 | * [常量](#constants)
41 | * [枚举类型](#enumerated-types)
42 | * [Case语句](#case-statements)
43 | * [私有属性](#private-properties)
44 | * [布尔值](#booleans)
45 | * [条件语句](#conditionals)
46 | * [三元操作符](#ternary-operator)
47 | * [Init方法](#init-methods)
48 | * [类构造方法](#class-constructor-methods)
49 | * [CGRect函数](#cgrect-functions)
50 | * [黄金路径](#golden-path)
51 | * [错误处理](#error-handling)
52 | * [单例模式](#singletons)
53 | * [换行符](#line-breaks)
54 | * [Xcode工程](#xcode-project)
55 |
56 |
57 | ## 语言
58 |
59 | 应该使用US英语.
60 |
61 | **应该:**
62 |
63 | ```objc
64 | UIColor *myColor = [UIColor whiteColor];
65 | ```
66 |
67 | **不应该:**
68 |
69 | ```objc
70 | UIColor *myColour = [UIColor whiteColor];
71 | ```
72 |
73 |
74 | ## 代码组织
75 |
76 | 在函数分组和protocol/delegate实现中使用`#pragma mark -`来分类方法,要遵循以下一般结构:
77 |
78 | ```objc
79 | #pragma mark - Lifecycle
80 | - (instancetype)init {}
81 | - (void)dealloc {}
82 | - (void)viewDidLoad {}
83 | - (void)viewWillAppear:(BOOL)animated {}
84 | - (void)didReceiveMemoryWarning {}
85 |
86 | #pragma mark - Custom Accessors
87 | - (void)setCustomProperty:(id)value {}
88 | - (id)customProperty {}
89 |
90 | #pragma mark - IBActions/Event Response
91 | - (IBAction)submitData:(id)sender {}
92 | - (void)someButtonDidPressed:(UIButton*)button
93 |
94 | #pragma mark - Protocol conformance
95 | #pragma mark - UITextFieldDelegate
96 | #pragma mark - UITableViewDataSource
97 | #pragma mark - UITableViewDelegate
98 |
99 | #pragma mark - Public
100 | - (void)publicMethod {}
101 |
102 | #pragma mark - Private
103 | - (void)privateMethod {}
104 |
105 | #pragma mark - NSCopying
106 | - (id)copyWithZone:(NSZone *)zone {}
107 |
108 | #pragma mark - NSObject
109 | - (NSString *)description {}
110 |
111 | ```
112 |
113 |
114 | ## 空格
115 |
116 | * 缩进使用**4**个空格,确保在Xcode偏好设置来设置。(raywenderlich.com使用**2**个空格)
117 | * 方法大括号和其他大括号(`if`/`else`/`switch`/`while` 等.)总是在同一行语句打开但在新行中关闭。
118 |
119 | **应该:**
120 |
121 | ```objc
122 | if (user.isHappy) {
123 | //Do something
124 | } else {
125 | //Do something else
126 | }
127 | ```
128 |
129 | **不应该:**
130 |
131 | ```objc
132 | if (user.isHappy)
133 | {
134 | //Do something
135 | }
136 | else {
137 | //Do something else
138 | }
139 | ```
140 |
141 | * 在方法之间应该有且只有一行,这样有利于在视觉上更清晰和更易于组织。在方法内的空白应该分离功能,但通常都抽离出来成为一个新方法。
142 | * 优先使用auto-synthesis。但如果有必要,`@synthesize` 和 `@dynamic`应该在实现中每个都声明新的一行。
143 | * 应该避免以冒号对齐的方式来调用方法。因为有时方法签名可能有3个以上的冒号和冒号对齐会使代码更加易读。请**不要**这样做,尽管冒号对齐的方法包含代码块,因为Xcode的对齐方式令它难以辨认。
144 |
145 | **应该:**
146 |
147 | ```objc
148 | // blocks are easily readable
149 | [UIView animateWithDuration:1.0 animations:^{
150 | // something
151 | } completion:^(BOOL finished) {
152 | // something
153 | }];
154 | ```
155 |
156 | **不应该:**
157 |
158 | ```objc
159 | // colon-aligning makes the block indentation hard to read
160 | [UIView animateWithDuration:1.0
161 | animations:^{
162 | // something
163 | }
164 | completion:^(BOOL finished) {
165 | // something
166 | }];
167 | ```
168 |
169 |
170 | ## 注释
171 |
172 | 当需要注释时,注释应该用来解释这段特殊代码**为什么**要这样做。任何被使用的注释都必须保持最新或被删除。
173 |
174 | 一般都避免使用块注释,因为代码尽可能做到自解释,只有当断断续续或几行代码时才需要注释。*例外:这不应用在生成文档的注释*
175 |
176 |
177 | ## 命名
178 |
179 | Apple命名规则尽可能坚持,特别是与这些相关的[memory management rules](https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/MemoryMgmt/Articles/MemoryMgmt.html) ([NARC](http://stackoverflow.com/a/2865194/340508))。
180 |
181 | 长的,描述性的方法和变量命名是好的。
182 |
183 | **应该:**
184 |
185 | ```objc
186 | UIButton *settingsButton;
187 | ```
188 |
189 | **不应该:**
190 |
191 | ```objc
192 | UIButton *setBut;
193 | ```
194 |
195 | 三个字符前缀应该经常用在类和常量命名,但在Core Data的实体名中应被忽略。对于官方的raywenderlich.com书、初学者工具包或教程,前缀'RWT'应该被使用。
196 |
197 | 常量应该使用驼峰式命名规则,所有的单词首字母大写和加上与类名有关的前缀。
198 |
199 | **应该:**
200 |
201 | ```objc
202 | static NSTimeInterval const RWTTutorialViewControllerNavigationFadeAnimationDuration = 0.3;
203 | ```
204 |
205 | **不应该:**
206 |
207 | ```objc
208 | static NSTimeInterval const fadetime = 1.7;
209 | ```
210 |
211 | 属性也是使用驼峰式,但首单词的首字母小写。对属性使用auto-synthesis,而不是手动编写@ synthesize语句,除非你有一个好的理由。
212 |
213 | **应该:**
214 |
215 | ```objc
216 | @property (strong, nonatomic) NSString *descriptiveVariableName;
217 | ```
218 |
219 | **不应该:**
220 |
221 | ```objc
222 | id varnm;
223 | ```
224 |
225 | ### 下划线
226 |
227 | 当使用属性时,实例变量应该使用`self.`来访问和改变。这就意味着所有属性将会视觉效果不同,因为它们前面都有`self.`。
228 |
229 | 但有一个特例:在初始化方法里,实例变量(例如,_variableName)应该直接被使用来避免getters/setters潜在的副作用。
230 |
231 | 局部变量不应该包含下划线。
232 |
233 |
234 | ## 方法
235 |
236 | 在方法签名中,应该在方法类型(-/+ 符号)之后有一个空格。在方法各个段之间应该也有一个空格(符合Apple的风格)。在参数之前应该包含一个具有描述性的关键字来描述参数。
237 |
238 | "and"这个词的用法应该保留。它不应该用于多个参数来说明,就像`initWithWidth:height`以下这个例子:
239 |
240 | **应该:**
241 | ```objc
242 | - (void)setExampleText:(NSString *)text image:(UIImage *)image;
243 | - (void)sendAction:(SEL)aSelector to:(id)anObject forAllCells:(BOOL)flag;
244 | - (id)viewWithTag:(NSInteger)tag;
245 | - (instancetype)initWithWidth:(CGFloat)width height:(CGFloat)height;
246 | ```
247 |
248 | **不应该:**
249 |
250 | ```objc
251 | -(void)setT:(NSString *)text i:(UIImage *)image;
252 | - (void)sendAction:(SEL)aSelector :(id)anObject :(BOOL)flag;
253 | - (id)taggedView:(NSInteger)tag;
254 | - (instancetype)initWithWidth:(CGFloat)width andHeight:(CGFloat)height;
255 | - (instancetype)initWith:(int)width and:(int)height; // Never do this.
256 | ```
257 |
258 | ## 变量
259 |
260 | 变量尽量以描述性的方式来命名。单个字符的变量命名应该尽量避免,除了在`for()`循环。
261 |
262 | 星号表示变量是指针。例如, `NSString *text` 既不是 `NSString* text` 也不是 `NSString * text`,除了一些特殊情况下常量。
263 |
264 | [私有变量](#private-properties) 应该尽可能代替实例变量的使用。尽管使用实例变量是一种有效的方式,但更偏向于使用属性来保持代码一致性。
265 |
266 | 通过使用'back'属性(_variable,变量名前面有下划线)直接访问实例变量应该尽量避免,除了在初始化方法(`init`, `initWithCoder:`, 等…),`dealloc` 方法和自定义的setters和getters。想了解关于如何在初始化方法和dealloc直接使用Accessor方法的更多信息,查看[这里](https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/MemoryMgmt/Articles/mmPractical.html#//apple_ref/doc/uid/TP40004447-SW6)
267 |
268 | **应该:**
269 |
270 | ```objc
271 | @interface RWTTutorial : NSObject
272 |
273 | @property (strong, nonatomic) NSString *tutorialName;
274 |
275 | @end
276 | ```
277 |
278 | **不应该:**
279 |
280 | ```objc
281 | @interface RWTTutorial : NSObject {
282 | NSString *tutorialName;
283 | }
284 | ```
285 |
286 |
287 | ## 属性特性
288 |
289 | 所有属性特性应该显式地列出来,有助于新手阅读代码。属性特性的顺序应该是storage、atomicity,与在Interface Builder连接UI元素时自动生成代码一致。
290 |
291 | **应该:**
292 |
293 | ```objc
294 | @property (weak, nonatomic) IBOutlet UIView *containerView;
295 | @property (strong, nonatomic) NSString *tutorialName;
296 | ```
297 |
298 | **不应该:**
299 |
300 | ```objc
301 | @property (nonatomic, weak) IBOutlet UIView *containerView;
302 | @property (nonatomic) NSString *tutorialName;
303 | ```
304 |
305 | NSString应该使用`copy` 而不是 `strong`的属性特性。
306 |
307 | 为什么?即使你声明一个`NSString`的属性,有人可能传入一个`NSMutableString`的实例,然后在你没有注意的情况下修改它。
308 |
309 | **应该:**
310 |
311 | ```objc
312 | @property (copy, nonatomic) NSString *tutorialName;
313 | ```
314 |
315 | **不应该:**
316 |
317 | ```objc
318 | @property (strong, nonatomic) NSString *tutorialName;
319 | ```
320 |
321 |
322 | ## 点符号语法
323 |
324 | 点语法是一种很方便封装访问方法调用的方式。当你使用点语法时,通过使用getter或setter方法,属性仍然被访问或修改。想了解更多,阅读[这里](https://developer.apple.com/library/ios/documentation/cocoa/conceptual/ProgrammingWithObjectiveC/EncapsulatingData/EncapsulatingData.html)
325 |
326 | 点语法应该**总是**被用来访问和修改属性,因为它使代码更加简洁。[]符号更偏向于用在其他例子。
327 |
328 |
329 |
330 | **应该:**
331 | ```objc
332 | NSInteger arrayCount = [self.array count];
333 | view.backgroundColor = [UIColor orangeColor];
334 | [UIApplication sharedApplication].delegate;
335 | ```
336 |
337 | **不应该:**
338 | ```objc
339 | NSInteger arrayCount = self.array.count;
340 | [view setBackgroundColor:[UIColor orangeColor]];
341 | UIApplication.sharedApplication.delegate;
342 | ```
343 |
344 |
345 | ## 字面值
346 |
347 | `NSString`, `NSDictionary`, `NSArray`, 和 `NSNumber`的字面值应该在创建这些类的不可变实例时被使用。请特别注意`nil`值不能传入`NSArray`和`NSDictionary`字面值,因为这样会导致crash。
348 |
349 | **应该:**
350 |
351 | ```objc
352 | NSArray *names = @[@"Brian", @"Matt", @"Chris", @"Alex", @"Steve", @"Paul"];
353 | NSDictionary *productManagers = @{@"iPhone": @"Kate", @"iPad": @"Kamal", @"Mobile Web": @"Bill"};
354 | NSNumber *shouldUseLiterals = @YES;
355 | NSNumber *buildingStreetNumber = @10018;
356 | ```
357 |
358 | **不应该:**
359 |
360 | ```objc
361 | NSArray *names = [NSArray arrayWithObjects:@"Brian", @"Matt", @"Chris", @"Alex", @"Steve", @"Paul", nil];
362 | NSDictionary *productManagers = [NSDictionary dictionaryWithObjectsAndKeys: @"Kate", @"iPhone", @"Kamal", @"iPad", @"Bill", @"Mobile Web", nil];
363 | NSNumber *shouldUseLiterals = [NSNumber numberWithBool:YES];
364 | NSNumber *buildingStreetNumber = [NSNumber numberWithInteger:10018];
365 | ```
366 |
367 | ## 常量
368 |
369 | 常量是容易重复被使用和无需通过查找和代替就能快速修改值。常量应该使用`static`来声明而不是使用`#define`,除非显式地使用宏。
370 |
371 | **应该:**
372 |
373 | ```objc
374 | static NSString * const RWTAboutViewControllerCompanyName = @"RayWenderlich.com";
375 |
376 | static CGFloat const RWTImageThumbnailHeight = 50.0;
377 | ```
378 |
379 | **不应该:**
380 |
381 | ```objc
382 | #define CompanyName @"RayWenderlich.com"
383 |
384 | #define thumbnailHeight 2
385 | ```
386 |
387 | ## 枚举类型
388 |
389 | 当使用`enum`时,推荐使用新的固定基本类型规格,因为它有更强的类型检查和代码补全。现在SDK有一个宏`NS_ENUM()`来帮助和鼓励你使用固定的基本类型。
390 |
391 | **例如:**
392 |
393 | ```objc
394 | typedef NS_ENUM(NSInteger, RWTLeftMenuTopItemType) {
395 | RWTLeftMenuTopItemMain,
396 | RWTLeftMenuTopItemShows,
397 | RWTLeftMenuTopItemSchedule
398 | };
399 | ```
400 |
401 | 你也可以显式地赋值(展示旧的k-style常量定义):
402 |
403 | ```objc
404 | typedef NS_ENUM(NSInteger, RWTGlobalConstants) {
405 | RWTPinSizeMin = 1,
406 | RWTPinSizeMax = 5,
407 | RWTPinCountMin = 100,
408 | RWTPinCountMax = 500,
409 | };
410 | ```
411 |
412 | 旧的k-style常量定义应该**避免**除非编写Core Foundation C的代码。
413 |
414 | **不应该:**
415 |
416 | ```objc
417 | enum GlobalConstants {
418 | kMaxPinSize = 5,
419 | kMaxPinCount = 500,
420 | };
421 | ```
422 |
423 |
424 | ## Case语句
425 |
426 | 大括号在case语句中并不是必须的,除非编译器强制要求。当一个case语句包含多行代码时,大括号应该加上。
427 |
428 | ```objc
429 | switch (condition) {
430 | case 1:
431 | // ...
432 | break;
433 | case 2: {
434 | // ...
435 | // Multi-line example using braces
436 | break;
437 | }
438 | case 3:
439 | // ...
440 | break;
441 | default:
442 | // ...
443 | break;
444 | }
445 |
446 | ```
447 | 有很多次,当相同代码被多个cases使用时,一个fall-through应该被使用。一个fall-through就是在case最后移除'break'语句,这样就能够允许执行流程跳转到下一个case值。为了代码更加清晰,一个fall-through需要注释一下。
448 |
449 |
450 | ```objc
451 | switch (condition) {
452 | case 1:
453 | // ** fall-through! **
454 | case 2:
455 | // code executed for values 1 and 2
456 | break;
457 | default:
458 | // ...
459 | break;
460 | }
461 |
462 | ```
463 |
464 | 当在switch使用枚举类型时,'default'是不需要的。例如:
465 |
466 | ```objc
467 | RWTLeftMenuTopItemType menuType = RWTLeftMenuTopItemMain;
468 |
469 | switch (menuType) {
470 | case RWTLeftMenuTopItemMain:
471 | // ...
472 | break;
473 | case RWTLeftMenuTopItemShows:
474 | // ...
475 | break;
476 | case RWTLeftMenuTopItemSchedule:
477 | // ...
478 | break;
479 | }
480 | ```
481 |
482 |
483 | ## 私有属性
484 |
485 | 私有属性应该在类的实现文件中的类扩展(匿名分类)中声明,命名分类(比如`RWTPrivate `或`private`)应该从不使用除非是扩展其他类。匿名分类应该通过使用+Private.h文件的命名规则暴露给测试。
486 |
487 | **例如:**
488 |
489 | ```objc
490 | @interface RWTDetailViewController ()
491 |
492 | @property (strong, nonatomic) GADBannerView *googleAdView;
493 | @property (strong, nonatomic) ADBannerView *iAdView;
494 | @property (strong, nonatomic) UIWebView *adXWebView;
495 |
496 | @end
497 | ```
498 |
499 |
500 | ## 布尔值
501 |
502 | Objective-C使用`YES`和`NO`。因为`true`和`false`应该只在CoreFoundation,C或C++代码使用。既然`nil`解析成`NO`,所以没有必要在条件语句比较。不要拿某样东西直接与`YES`比较,因为`YES`被定义为1和一个`BOOL`能被设置为8位。
503 |
504 | 这是为了在不同文件保持一致性和在视觉上更加简洁而考虑。
505 |
506 | **应该:**
507 |
508 | ```objc
509 | if (someObject) {}
510 | if (![anotherObject boolValue]) {}
511 | ```
512 |
513 | **不应该:**
514 |
515 | ```objc
516 | if (someObject == nil) {}
517 | if ([anotherObject boolValue] == NO) {}
518 | if (isAwesome == YES) {} // Never do this.
519 | if (isAwesome == true) {} // Never do this.
520 | ```
521 |
522 | 如果`BOOL`属性的名字是一个形容词,属性就能忽略"is"前缀,但要指定get访问器的惯用名称。例如:
523 |
524 | ```objc
525 | @property (assign, getter=isEditable) BOOL editable;
526 | ```
527 |
528 | 文字和例子从这里引用[Cocoa Naming Guidelines](https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/CodingGuidelines/Articles/NamingIvarsAndTypes.html#//apple_ref/doc/uid/20001284-BAJGIIJE)
529 |
530 |
531 | ## 条件语句
532 |
533 | 条件语句主体为了防止出错应该使用大括号包围,即使条件语句主体能够不用大括号编写(如,只用一行代码)。这些错误包括添加第二行代码和期望它成为if语句;还有,[even more dangerous defect](http://programmers.stackexchange.com/a/16530)可能发生在if语句里面一行代码被注释了,然后下一行代码不知不觉地成为if语句的一部分。除此之外,这种风格与其他条件语句的风格保持一致,所以更加容易阅读。
534 |
535 | **应该:**
536 |
537 | ```objc
538 | if (!error) {
539 | return success;
540 | }
541 | ```
542 |
543 | **不应该:**
544 |
545 | ```objc
546 | if (!error)
547 | return success;
548 | ```
549 |
550 | 或
551 |
552 | ```objc
553 | if (!error) return success;
554 | ```
555 |
556 |
557 | ### 三元操作符
558 |
559 | 当需要提高代码的清晰性和简洁性时,三元操作符`?:`才会使用。单个条件求值常常需要它。多个条件求值时,如果使用`if`语句或重构成实例变量时,代码会更加易读。一般来说,最好使用三元操作符是在根据条件来赋值的情况下。
560 |
561 | Non-boolean的变量与某东西比较,加上括号()会提高可读性。如果被比较的变量是boolean类型,那么就不需要括号。
562 |
563 | **应该:**
564 |
565 | ```objc
566 | NSInteger value = 5;
567 | result = (value != 0) ? x : y;
568 |
569 | BOOL isHorizontal = YES;
570 | result = isHorizontal ? x : y;
571 | ```
572 |
573 | **不应该:**
574 |
575 | ```objc
576 | result = a > b ? x = c > d ? c : d : y;
577 | ```
578 |
579 |
580 | ## Init方法
581 |
582 | Init方法应该遵循Apple生成代码模板的命名规则。返回类型应该使用`instancetype`而不是`id`
583 |
584 | ```objc
585 | - (instancetype)init {
586 | self = [super init];
587 | if (self) {
588 | // ...
589 | }
590 | return self;
591 | }
592 | ```
593 |
594 | 查看关于instancetype的文章[Class Constructor Methods](#class-constructor-methods)
595 |
596 |
597 | ## 类构造方法
598 |
599 | 当类构造方法被使用时,它应该返回类型是`instancetype `而不是`id`。这样确保编译器正确地推断结果类型。
600 |
601 |
602 | ```objc
603 | @interface Airplane
604 | + (instancetype)airplaneWithType:(RWTAirplaneType)type;
605 | @end
606 | ```
607 | 关于更多instancetype信息,请查看[NSHipster.com](http://nshipster.com/instancetype/)
608 |
609 |
610 | ## CGRect函数
611 |
612 | 当访问`CGRect`里的`x`, `y`, `width`, 或 `height`时,应该使用[`CGGeometry`函数](http://developer.apple.com/library/ios/#documentation/graphicsimaging/reference/CGGeometry/Reference/reference.html)而不是直接通过结构体来访问。引用Apple的`CGGeometry `:
613 |
614 | > 在这个参考文档中所有的函数,接受CGRect结构体作为输入,在计算它们结果时隐式地标准化这些rectangles。因此,你的应用程序应该避免直接访问和修改保存在CGRect数据结构中的数据。相反,使用这些函数来操纵rectangles和获取它们的特性。
615 |
616 |
617 | **应该:**
618 |
619 | ```objc
620 | CGRect frame = self.view.frame;
621 |
622 | CGFloat x = CGRectGetMinX(frame);
623 | CGFloat y = CGRectGetMinY(frame);
624 | CGFloat width = CGRectGetWidth(frame);
625 | CGFloat height = CGRectGetHeight(frame);
626 | CGRect frame = CGRectMake(0.0, 0.0, width, height);
627 | ```
628 |
629 | **不应该:**
630 |
631 | ```objc
632 | CGRect frame = self.view.frame;
633 |
634 | CGFloat x = frame.origin.x;
635 | CGFloat y = frame.origin.y;
636 | CGFloat width = frame.size.width;
637 | CGFloat height = frame.size.height;
638 | CGRect frame = (CGRect){ .origin = CGPointZero, .size = frame.size };
639 | ```
640 |
641 |
642 | ## 黄金路径
643 |
644 | 当使用条件语句编码时,左手边的代码应该是"golden" 或 "happy"路径。也就是不要嵌套`if`语句,多个返回语句也是OK。
645 |
646 | **应该:**
647 |
648 | ```objc
649 | - (void)someMethod {
650 | if (![someOther boolValue]) {
651 | return;
652 | }
653 |
654 | //Do something important
655 | }
656 | ```
657 |
658 | **不应该:**
659 |
660 | ```objc
661 | - (void)someMethod {
662 | if ([someOther boolValue]) {
663 | //Do something important
664 | }
665 | }
666 | ```
667 |
668 |
669 | ## 错误处理
670 |
671 | 当方法通过引用来返回一个错误参数,判断返回值而不是错误变量。
672 |
673 | **应该:**
674 | ```objc
675 | NSError *error;
676 | if (![self trySomethingWithError:&error]) {
677 | // Handle Error
678 | }
679 | ```
680 |
681 | **不应该:**
682 | ```objc
683 | NSError *error;
684 | [self trySomethingWithError:&error];
685 | if (error) {
686 | // Handle Error
687 | }
688 | ```
689 |
690 | 在成功的情况下,有些Apple的APIs记录垃圾值(garbage values)到错误参数(如果non-NULL),那么判断错误值会导致false负值和crash。
691 |
692 |
693 | ## 单例模式
694 |
695 | 单例对象应该使用线程安全模式来创建共享实例。
696 |
697 | ```objc
698 | + (instancetype)sharedInstance {
699 | static id sharedInstance = nil;
700 |
701 | static dispatch_once_t onceToken;
702 | dispatch_once(&onceToken, ^{
703 | sharedInstance = [[self alloc] init];
704 | });
705 |
706 | return sharedInstance;
707 | }
708 | ```
709 |
710 | 这会防止[possible and sometimes prolific crashes](http://cocoasamurai.blogspot.com/2011/04/singletons-your-doing-them-wrong.html).
711 |
712 |
713 | ## 换行符
714 |
715 | 换行符是一个很重要的主题,因为它的风格指南主要为了打印和网上的可读性。
716 |
717 | 例如:
718 |
719 | ```objc
720 | self.productsRequest = [[SKProductsRequest alloc] initWithProductIdentifiers:productIdentifiers];
721 | ```
722 |
723 | 一行很长的代码应该分成两行代码,下一行用两个空格隔开。
724 |
725 | ```objc
726 | self.productsRequest = [[SKProductsRequest alloc]
727 | initWithProductIdentifiers:productIdentifiers];
728 | ```
729 |
730 |
731 | ## Xcode工程
732 |
733 | 物理文件应该与Xcode工程文件保持同步来避免文件扩张。任何Xcode分组的创建应该在文件系统的文件体现。代码不仅是根据**类型**来分组,而且还可以根据**功能**来分组,这样代码更加清晰。
734 |
735 | 尽可能在target的Build Settings打开"Treat Warnings as Errors,和启用以下[additional warnings](http://boredzo.org/blog/archives/2009-11-07/warnings)。如果你需要忽略特殊的警告,使用 [Clang's pragma feature](http://clang.llvm.org/docs/UsersManual.html#controlling-diagnostics-via-pragmas)。
736 |
737 | # 其他Objective-C编码规范
738 |
739 | 如果我们的编码规范不符合你的口味,可以查看其他的编码规范:
740 |
741 | * [Robots & Pencils](https://github.com/RobotsAndPencils/objective-c-style-guide)
742 | * [New York Times](https://github.com/NYTimes/objective-c-style-guide)
743 | * [Google](http://google-styleguide.googlecode.com/svn/trunk/objcguide.xml)
744 | * [GitHub](https://github.com/github/objective-c-conventions)
745 | * [Adium](https://trac.adium.im/wiki/CodingStyle)
746 | * [Sam Soffes](https://gist.github.com/soffes/812796)
747 | * [CocoaDevCentral](http://cocoadevcentral.com/articles/000082.php)
748 | * [Luke Redpath](http://lukeredpath.co.uk/blog/my-objective-c-style-guide.html)
749 | * [Marcus Zarra](http://www.cimgf.com/zds-code-style-guide/)
750 |
751 |
--------------------------------------------------------------------------------