1 # 译者的话
2
3
4
5 代码风格的重要性对于一个团队和项目来说不言而喻。网上有许多 Objective-
C 的代码风格,但这份简洁而又最符合苹果的规范,同时有助于养成良好的代码习惯,也是我们团队一直遵循的代码风格。
6
7
8
9 原文在[这里][original_link]。
10
11 本人才疏学浅,如果有任何翻译不当欢迎在 [Issues][Issues_link] 中反馈或者直接 [Fork][Fork_link] 。
12
13
14
15 [original_link]:https:
//github.com/NYTimes/objective-c-style-guide
16
17
18
19 [Issues_link]:https:
//github.com/VincentSit/NYTimes-Objective-C-Style-Guide-ZH/issues
20
21
22
23 [Fork_link]:https:
//github.com/NYTimes/objective-c-style-guide/fork
24
25
26
27 ----
28
29
30
31 # 纽约时报 移动团队 Objective-
C 规范指南
32
33
34
35 这份规范指南概括了纽约时报 iOS 团队的代码约定。
36
37
38
39 ## 介绍
40
41
42
43 关于这个编程语言的所有规范,如果这里没有写到,那就在苹果的文档里:
44
45
46
47 * [Objective-
C 编程语言][Introduction_1]
48
49 *
[Cocoa 基本原理指南][Introduction_2]
50
51 *
[Cocoa 编码指南][Introduction_3]
52
53 *
[iOS 应用编程指南][Introduction_4]
54
55
56
57 [Introduction_1]:http:
//developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/ObjectiveC/Introduction/introObjectiveC.html
58
59
60
61 [Introduction_2]:https:
//developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/CocoaFundamentals/Introduction/Introduction.html
62
63
64
65 [Introduction_3]:https:
//developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/CodingGuidelines/CodingGuidelines.html
66
67
68
69 [Introduction_4]:http:
//developer.apple.com/library/ios/#documentation/iphone/conceptual/iphoneosprogrammingguide/Introduction/Introduction.html
70
71
72
73
74
75 ## 目录
76
77
78
79 *
[点语法](#点语法)
80
81 *
[间距](#间距)
82
83 *
[条件判断](#条件判断)
84
85 *
[三目运算符](#三目运算符)
86
87 *
[错误处理](#错误处理)
88
89 *
[方法](#方法)
90
91 *
[变量](#变量)
92
93 *
[命名](#命名)
94
95 *
[注释](#注释)
96
97 * [Init 和 Dealloc](#init-和-
dealloc)
98
99 *
[字面量](#字面量)
100
101 * [CGRect 函数](#CGRect-
函数)
102
103 *
[常量](#常量)
104
105 *
[枚举类型](#枚举类型)
106
107 *
[位掩码](#位掩码)
108
109 *
[私有属性](#私有属性)
110
111 *
[图片命名](#图片命名)
112
113 *
[布尔](#布尔)
114
115 *
[单例](#单例)
116
117 *
[导入](#导入)
118
119 * [Xcode 工程](#Xcode-
工程)
120
121
122
123 ## 点语法
124
125
126
127 应该 **始终**
使用点语法来访问或者修改属性,访问其他实例时首选括号。
128
129
130
131 **推荐:**
132
133 ```objc
134
135 view.backgroundColor =
[UIColor orangeColor];
136
137 [UIApplication sharedApplication].
delegate;
138
139 ```
140
141
142
143 **反对:**
144
145 ```objc
146
147 [view setBackgroundColor:[UIColor orangeColor]];
148
149 UIApplication.sharedApplication.
delegate;
150
151 ```
152
153
154
155 ## 间距
156
157
158
159 * 一个缩进使用
4 个空格,永远不要使用制表符(tab)缩进。请确保在 Xcode 中设置了此偏好。
160
161 * 方法的大括号和其他的大括号(`
if`/`
else`/`
switch`/`
while` 等等)始终和声明在同一行开始,在新的一行结束。
162
163
164
165 **推荐:**
166
167 ```objc
168
169 if (user.isHappy) {
170
171 // Do something
172
173 }
174
175 else {
176
177 // Do something else
178
179 }
180
181 ```
182
183 *
方法之间应该正好空一行,这有助于视觉清晰度和代码组织性。在方法中的功能块之间应该使用空白分开,但往往可能应该创建一个新的方法。
184
185 * `
@synthesize` 和 `@dynamic` 在实现中每个都应该占一个新行。
186
187
188
189
190
191 ## 条件判断
192
193
194
195 条件判断主体部分应该始终使用大括号括住来防止[出错][Condiationals_1],即使它可以不用大括号(例如它只需要一行)。这些错误包括添加第二行(代码)并希望它是
if 语句的一部分时。还有另外一种[更危险的][Condiationals_2],当
if 语句里面的一行被注释掉,下一行就会在不经意间成为了这个
if 语句的一部分。此外,这种风格也更符合所有其他的条件判断,因此也更容易检查。
196
197
198
199 **推荐:**
200
201 ```objc
202
203 if (!
error) {
204
205 return success;
206
207 }
208
209 ```
210
211
212
213 **反对:**
214
215 ```objc
216
217 if (!
error)
218
219 return success;
220
221 ```
222
223
224
225 或
226
227
228
229 ```objc
230
231 if (!error)
return success;
232
233 ```
234
235
236
237
238
239 [Condiationals_1]:(https:
//github.com/NYTimes/objective-c-style-guide/issues/26#issuecomment-22074256)
240
241 [Condiationals_2]:http:
//programmers.stackexchange.com/a/16530
242
243
244
245 ### 三目运算符
246
247
248
249 三目运算符,? ,只有当它可以增加代码清晰度或整洁时才使用。单一的条件都应该优先考虑使用。多条件时通常使用
if 语句会更易懂,或者重构为实例变量。
250
251
252
253 **推荐:**
254
255 ```objc
256
257 result = a > b ?
x : y;
258
259 ```
260
261
262
263 **反对:**
264
265 ```objc
266
267 result = a > b ? x = c > d ?
c : d : y;
268
269 ```
270
271
272
273 ## 错误处理
274
275
276
277 当引用一个返回错误参数(error parameter)的方法时,应该针对返回值,而非错误变量。
278
279
280
281 **推荐:**
282
283 ```objc
284
285 NSError *
error;
286
287 if (![self trySomethingWithError:&
error]) {
288
289 // 处理错误
290
291 }
292
293 ```
294
295
296
297 **反对:**
298
299 ```objc
300
301 NSError *
error;
302
303 [self trySomethingWithError:&
error];
304
305 if (error) {
306
307 // 处理错误
308
309 }
310
311 ```
312
313 一些苹果的 API 在成功的情况下会写一些垃圾值给错误参数(如果非空),所以针对错误变量可能会造成虚假结果(以及接下来的崩溃)。
314
315
316
317 ## 方法
318
319
320
321 在方法签名中,在 -/+
符号后应该有一个空格。方法片段之间也应该有一个空格。
322
323
324
325 **推荐:**
326
327 ```objc
328
329 - (
void)setExampleText:(NSString *)text image:(UIImage *
)image;
330
331 ```
332
333
334
335 ## 变量
336
337
338
339 变量名应该尽可能命名为描述性的。除了 `
for()` 循环外,其他情况都应该避免使用单字母的变量名。
340
341 星号表示指针属于变量,例如:`NSString *text` 不要写成 `NSString* text` 或者 `NSString *
text` ,常量除外。
342
343 尽量定义属性来代替直接使用实例变量。除了初始化方法(`init`, `initWithCoder:`,等), `dealloc` 方法和自定义的 setters 和 getters 内部,应避免直接访问实例变量。更多有关在初始化方法和 dealloc 方法中使用访问器方法的信息,参见[这里][Variables_1]。
344
345
346
347
348
349 **推荐:**
350
351
352
353 ```objc
354
355 @interface NYTSection: NSObject
356
357
358
359 @property (nonatomic) NSString *
headline;
360
361
362
363 @end
364
365 ```
366
367
368
369 **反对:**
370
371
372
373 ```objc
374
375 @interface NYTSection : NSObject {
376
377 NSString *
headline;
378
379 }
380
381 ```
382
383
384
385 [Variables_1]:https:
//developer.apple.com/library/mac/documentation/Cocoa/Conceptual/MemoryMgmt/Articles/mmPractical.html#//apple_ref/doc/uid/TP40004447-SW6
386
387
388
389 #### 变量限定符
390
391
392
393 当涉及到[在 ARC 中被引入][Variable_Qualifiers_1]变量限定符时,
394
395 限定符 (`__strong`, `__weak`, `__unsafe_unretained`, `__autoreleasing`) 应该位于星号和变量名之间,如:`NSString *
__weak text`。
396
397
398
399 [Variable_Qualifiers_1]:(https:
//developer.apple.com/library/ios/releasenotes/objectivec/rn-transitioningtoarc/Introduction/Introduction.html#//apple_ref/doc/uid/TP40011226-CH1-SW4)
400
401
402
403 ## 命名
404
405
406
407 尽可能遵守苹果的命名约定,尤其那些涉及到[内存管理规则][Naming_1],([NARC][Naming_2])的。
408
409
410
411 长的和描述性的方法名和变量名都不错。
412
413
414
415 **推荐:**
416
417
418
419 ```objc
420
421 UIButton *
settingsButton;
422
423 ```
424
425
426
427 **反对:**
428
429
430
431 ```objc
432
433 UIButton *
setBut;
434
435 ```
436
437 类名和常量应该始终使用三个字母的前缀(例如 `NYT`),但 Core Data 实体名称可以省略。为了代码清晰,常量应该使用相关类的名字作为前缀并使用驼峰命名法。
438
439
440
441 **推荐:**
442
443
444
445 ```objc
446
447 static const NSTimeInterval NYTArticleViewControllerNavigationFadeAnimationDuration =
0.3;
448
449 ```
450
451
452
453 **反对:**
454
455
456
457 ```objc
458
459 static const NSTimeInterval fadetime =
1.7;
460
461 ```
462
463
464
465 属性和局部变量应该使用驼峰命名法并且首字母小写。
466
467
468
469 为了保持一致,实例变量应该使用驼峰命名法命名,并且首字母小写,以下划线为前缀。这与 LLVM 自动合成的实例变量相一致。
470
471 **如果 LLVM 可以自动合成变量,那就让它自动合成。**
472
473
474
475 **推荐:**
476
477
478
479 ```objc
480
481 @synthesize descriptiveVariableName =
_descriptiveVariableName;
482
483 ```
484
485
486
487 **反对:**
488
489
490
491 ```objc
492
493 id varnm;
494
495 ```
496
497
498
499 [Naming_1]:https:
//developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/MemoryMgmt/Articles/MemoryMgmt.html
500
501
502
503 [Naming_2]:http:
//stackoverflow.com/a/2865194/340508
504
505
506
507 ## 注释
508
509
510
511 当需要的时候,注释应该被用来解释 **为什么**
特定代码做了某些事情。所使用的任何注释必须保持最新否则就删除掉。
512
513
514
515 通常应该避免一大块注释,代码就应该尽量作为自身的文档,只需要隔几行写几句说明。这并不适用于那些用来生成文档的注释。
516
517
518
519
520
521 ## init 和 dealloc
522
523
524
525 `dealloc` 方法应该放在实现文件的最上面,并且刚好在 `
@synthesize` 和 `@dynamic` 语句的后面。在任何类中,`init` 都应该直接放在 `dealloc` 方法的下面。
526
527
528
529 `init` 方法的结构应该像这样:
530
531
532
533 ```objc
534
535 -
(instancetype)init {
536
537 self = [super init];
// 或者调用指定的初始化方法
538
539 if (self) {
540
541 // Custom initialization
542
543 }
544
545
546
547 return self;
548
549 }
550
551 ```
552
553
554
555 ## 字面量
556
557
558
559 每当创建 `NSString`, `NSDictionary`, `NSArray`,和 `NSNumber` 类的不可变实例时,都应该使用字面量。要注意 `nil` 值不能传给 `NSArray` 和 `NSDictionary` 字面量,这样做会导致崩溃。
560
561
562
563 **推荐:**
564
565
566
567 ```objc
568
569 NSArray *names = @[
@"Brian",
@"Matt",
@"Chris",
@"Alex",
@"Steve",
@"Paul"];
570
571 NSDictionary *productManagers = @{
@"iPhone" :
@"Kate",
@"iPad" :
@"Kamal",
@"Mobile Web" :
@"Bill"};
572
573 NSNumber *shouldUseLiterals =
@YES;
574
575 NSNumber *buildingZIPCode = @
10018;
576
577 ```
578
579
580
581 **反对:**
582
583
584
585 ```objc
586
587 NSArray *names = [NSArray arrayWithObjects:
@"Brian",
@"Matt",
@"Chris",
@"Alex",
@"Steve",
@"Paul", nil];
588
589 NSDictionary *productManagers = [NSDictionary dictionaryWithObjectsAndKeys:
@"Kate",
@"iPhone",
@"Kamal",
@"iPad",
@"Bill",
@"Mobile Web", nil];
590
591 NSNumber *shouldUseLiterals =
[NSNumber numberWithBool:YES];
592
593 NSNumber *buildingZIPCode = [NSNumber numberWithInteger:
10018];
594
595 ```
596
597
598
599 ## CGRect 函数
600
601
602
603 当访问一个 `CGRect` 的 `x`, `y`, `width`, `height` 时,应该使用[`CGGeometry` 函数][CGRect-
Functions_1]代替直接访问结构体成员。苹果的 `CGGeometry` 参考中说到:
604
605
606
607 > 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.
608
609
610
611 **推荐:**
612
613
614
615 ```objc
616
617 CGRect frame =
self.view.frame;
618
619
620
621 CGFloat x =
CGRectGetMinX(frame);
622
623 CGFloat y =
CGRectGetMinY(frame);
624
625 CGFloat width =
CGRectGetWidth(frame);
626
627 CGFloat height =
CGRectGetHeight(frame);
628
629 ```
630
631
632
633 **反对:**
634
635
636
637 ```objc
638
639 CGRect frame =
self.view.frame;
640
641
642
643 CGFloat x =
frame.origin.x;
644
645 CGFloat y =
frame.origin.y;
646
647 CGFloat width =
frame.size.width;
648
649 CGFloat height =
frame.size.height;
650
651 ```
652
653
654
655 [CGRect-Functions_1]:http:
//developer.apple.com/library/ios/#documentation/graphicsimaging/reference/CGGeometry/Reference/reference.html
656
657
658
659 ## 常量
660
661
662
663 常量首选内联字符串字面量或数字,因为常量可以轻易重用并且可以快速改变而不需要查找和替换。常量应该声明为 `
static` 常量而不是 `
#define` ,除非非常明确地要当做宏来使用。
664
665
666
667 **推荐:**
668
669
670
671 ```objc
672
673 static NSString *
const NYTAboutViewControllerCompanyName =
@"The New York Times Company";
674
675
676
677 static const CGFloat NYTImageThumbnailHeight =
50.0;
678
679 ```
680
681
682
683 **反对:**
684
685
686
687 ```objc
688
689 #define CompanyName @"The New York Times Company"
690
691
692
693 #define thumbnailHeight 2
694
695 ```
696
697
698
699 ## 枚举类型
700
701
702
703 当使用 `
enum` 时,建议使用新的基础类型规范,因为它具有更强的类型检查和代码补全功能。现在 SDK 包含了一个宏来鼓励使用使用新的基础类型 -
`NS_ENUM()`
704
705
706
707 **推荐:**
708
709
710
711 ```objc
712
713 typedef NS_ENUM(NSInteger, NYTAdRequestState) {
714
715 NYTAdRequestStateInactive,
716
717 NYTAdRequestStateLoading
718
719 };
720
721 ```
722
723
724
725 ## 位掩码
726
727
728
729 当用到位掩码时,使用 `NS_OPTIONS` 宏。
730
731
732
733 **举例:**
734
735
736
737 ```objc
738
739 typedef NS_OPTIONS(NSUInteger, NYTAdCategory) {
740
741 NYTAdCategoryAutos =
1 <<
0,
742
743 NYTAdCategoryJobs =
1 <<
1,
744
745 NYTAdCategoryRealState =
1 <<
2,
746
747 NYTAdCategoryTechnology =
1 <<
3
748
749 };
750
751 ```
752
753
754
755
756
757 ## 私有属性
758
759
760
761 私有属性应该声明在类实现文件的延展(匿名的类目)中。有名字的类目(例如 `NYTPrivate` 或 `
private`)永远都不应该使用,除非要扩展其他类。
762
763
764
765 **推荐:**
766
767
768
769 ```objc
770
771 @interface NYTAdvertisement ()
772
773
774
775 @property (nonatomic, strong) GADBannerView *
googleAdView;
776
777 @property (nonatomic, strong) ADBannerView *
iAdView;
778
779 @property (nonatomic, strong) UIWebView *
adXWebView;
780
781
782
783 @end
784
785 ```
786
787
788
789 ## 图片命名
790
791
792
793 图片名称应该被统一命名以保持组织的完整。它们应该被命名为一个说明它们用途的驼峰式字符串,其次是自定义类或属性的无前缀名字(如果有的话),然后进一步说明颜色 和/
或 展示位置,最后是它们的状态。
794
795
796
797 **推荐:**
798
799
800
801 * `RefreshBarButtonItem` / `RefreshBarButtonItem@2x` 和 `RefreshBarButtonItemSelected` /
`RefreshBarButtonItemSelected@2x`
802
803 * `ArticleNavigationBarWhite` / `ArticleNavigationBarWhite@2x` 和 `ArticleNavigationBarBlackSelected` /
`ArticleNavigationBarBlackSelected@2x`.
804
805
806
807 图片目录中被用于类似目的的图片应归入各自的组中。
808
809
810
811
812
813 ## 布尔
814
815
816
817 因为 `nil` 解析为 `NO`,所以没有必要在条件中与它进行比较。永远不要直接和 `YES` 进行比较,因为 `YES` 被定义为
1,而 `BOOL` 可以多达
8 位。
818
819
820
821 这使得整个文件有更多的一致性和更大的视觉清晰度。
822
823
824
825 **推荐:**
826
827
828
829 ```objc
830
831 if (!
someObject) {
832
833 }
834
835 ```
836
837
838
839 **反对:**
840
841
842
843 ```objc
844
845 if (someObject ==
nil) {
846
847 }
848
849 ```
850
851
852
853 -----
854
855
856
857 **对于 `BOOL` 来说, 这有两种用法:**
858
859
860
861 ```objc
862
863 if (isAwesome)
864
865 if (!
[someObject boolValue])
866
867 ```
868
869
870
871 **反对:**
872
873
874
875 ```objc
876
877 if ([someObject boolValue] ==
NO)
878
879 if (isAwesome == YES)
// 永远别这么做
880
881 ```
882
883
884
885 -----
886
887
888
889 如果一个 `BOOL` 属性名称是一个形容词,属性可以省略 “
is” 前缀,但为
get 访问器指定一个惯用的名字,例如:
890
891
892
893 ```objc
894
895 @property (assign, getter=
isEditable) BOOL editable;
896
897 ```
898
899
900
901 内容和例子来自 [Cocoa 命名指南][Booleans_1] 。
902
903
904
905 [Booleans_1]:https:
//developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/CodingGuidelines/Articles/NamingIvarsAndTypes.html#//apple_ref/doc/uid/20001284-BAJGIIJE
906
907
908
909
910
911 ## 单例
912
913
914
915 单例对象应该使用线程安全的模式创建共享的实例。
916
917
918
919 ```objc
920
921 +
(instancetype)sharedInstance {
922
923 static id sharedInstance =
nil;
924
925
926
927 static dispatch_once_t onceToken;
928
929 dispatch_once(&onceToken, ^
{
930
931 sharedInstance =
[[self alloc] init];
932
933 });
934
935
936
937 return sharedInstance;
938
939 }
940
941 ```
942
943 这将会预防[有时可能产生的许多崩溃][Singletons_1]。
944
945
946
947 [Singletons_1]:http:
//cocoasamurai.blogspot.com/2011/04/singletons-your-doing-them-wrong.html
948
949
950
951 ## 导入
952
953
954
955 如果有一个以上的 import 语句,就对这些语句进行[分组][Import_1]。每个分组的注释是可选的。
956
957 注:对于模块使用 [@import][Import_2] 语法。
958
959
960
961 ```objc
962
963 // Frameworks
964
965 @import QuartzCore;
966
967
968
969 // Models
970
971 #import "NYTUser.h"
972
973
974
975 // Views
976
977 #import "NYTButton.h"
978
979 #import "NYTUserView.h"
980
981 ```
982
983
984
985
986
987 [Import_1]: http:
//ashfurrow.com/blog/structuring-modern-objective-c
988
989 [Import_2]: http:
//clang.llvm.org/docs/Modules.html#using-modules
990
991
992
993 ## Xcode 工程
994
995
996
997 为了避免文件杂乱,物理文件应该保持和 Xcode 项目文件同步。Xcode 创建的任何组(group)都必须在文件系统有相应的映射。为了更清晰,代码不仅应该按照类型进行分组,也可以根据功能进行分组。
998
999
1000
1001
1002
1003 如果可以的话,尽可能一直打开 target Build Settings 中
"Treat Warnings as Errors" 以及一些[额外的警告][Xcode-project_1]。如果你需要忽略指定的警告,使用 [Clang 的编译特性][Xcode-
project_2] 。
1004
1005
1006
1007
1008
1009 [Xcode-project_1]:http:
//boredzo.org/blog/archives/2009-11-07/warnings
1010
1011
1012
1013 [Xcode-project_2]:http:
//clang.llvm.org/docs/UsersManual.html#controlling-diagnostics-via-pragmas
1014
1015
1016
1017
1018
1019 # 其他 Objective-
C 风格指南
1020
1021
1022
1023 如果感觉我们的不太符合你的口味,可以看看下面的风格指南:
1024
1025
1026
1027 * [Google](http:
//google-styleguide.googlecode.com/svn/trunk/objcguide.xml)
1028
1029 * [GitHub](https:
//github.com/github/objective-c-conventions)
1030
1031 * [Adium](https:
//trac.adium.im/wiki/CodingStyle)
1032
1033 * [Sam Soffes](https:
//gist.github.com/soffes/812796)
1034
1035 * [CocoaDevCentral](http:
//cocoadevcentral.com/articles/000082.php)
1036
1037 * [Luke Redpath](http:
//lukeredpath.co.uk/blog/my-objective-c-style-guide.html)
1038
1039 * [Marcus Zarra](http:
//www.cimgf.com/zds-code-style-guide/)
1040
1041
转载于:https://www.cnblogs.com/fshmjl/p/4852461.html