命名
名称应在合理范围内尽可能具有描述性。遵循标准的 Objective-C 命名规则 。
避免使用非标准缩写(包括非标准的首字母缩略词(Acronyms)和首字母组合词(Initialisms))。不要担心节省水平空间,因为让新读者立即理解你的代码要重要得多。例如:
// GOOD:
// 好的名称。
int numberOfErrors = 0;
int completedConnectionsCount = 0;
tickets = [[NSMutableArray alloc] init];
userInfo = [someObject object];
port = [network port];
NSDate *gAppLaunchDate;// AVOID:
// 应避免的名称。
int w;
int nerr;
int nCompConns;
tix = [[NSMutableArray alloc] init];
obj = [someObject object];
p = [network port];任何类、分类(Category)、方法、函数或变量名称中的首字母缩略词和首字母组合词 应全部大写(包括名称开头)。这遵循了 Apple 在名称中对 URL、ID、TIFF 和 EXIF 等首字母缩略词使用全部大写的标准。
C 函数和 typedef 的名称应大写并根据周围代码的情况使用驼峰命名法(Camel Case)。
包容性语言
在所有代码中,包括命名和注释,使用包容性语言,避免使用其他程序员可能觉得不尊重或冒犯的术语(如 “master” 和 “slave”、“blacklist” 和 “whitelist”、或 “redline”),即使这些术语表面上也有中性含义。同样,使用性别中立的语言,除非你指的是特定的人(并使用他们的代词)。例如,对于未指定性别的人使用 “they”/“them”/“their”(即使是单数),对于非人类使用 “it”/“its”。
文件名
文件名应反映其包含的类实现的名称——包括大小写。
遵循你的项目所使用的约定。
文件扩展名应如下所示:
| 扩展名 | 类型 |
|---|---|
| .h | C/C++/Objective-C 头文件 |
| .m | Objective-C 实现文件 |
| .mm | Objective-C++ 实现文件 |
| .cc | 纯 C++ 实现文件 |
| .c | C 实现文件 |
可能在项目间共享或在大型项目中使用的文件应有一个明确唯一的名称,通常包含项目或类的前缀。
分类的文件名应包含被扩展的类名,如 GTMNSString+Utils.h 或 NSTextView+GTMAutocomplete.h
前缀
前缀在 Objective-C 中通常是必需的,以避免全局命名空间(Global Namespace)中的命名冲突。类、协议(Protocol)、全局函数和全局常量通常应使用以大写字母开头、后跟一个或多个大写字母或数字的前缀来命名。
警告:Apple 保留了两个字母的前缀——参见 Conventions in Programming with Objective-C ——因此至少使用三个字符的前缀被认为是最佳实践。
// GOOD:
/** 一个示例错误域。 */
GTM_EXTERN NSString *GTMExampleErrorDomain;
/** 获取默认时区。 */
GTM_EXTERN NSTimeZone *GTMGetDefaultTimeZone(void);
/** 一个示例委托。 */
@protocol GTMExampleDelegate <NSObject>
@end
/** 一个示例类。 */
@interface GTMExample : NSObject
@end
类名
类名(以及分类名和协议名)应以大写字母开头,使用混合大小写来分隔单词。
在多个应用程序间共享的代码中的类和协议必须有一个适当的前缀(如 GTMSendMessage)。前缀对于其他类和协议是推荐的,但不是必需的。
分类命名
分类名称应以适当的前缀开头,表明该分类属于某个项目或可供通用使用。
分类源文件名应以被扩展的类开头,后跟加号和分类名称,例如 NSString+GTMParsing.h。分类中的方法应以分类名称所用前缀的小写版本加下划线作为前缀(例如 gtm_myCategoryMethodOnAString:),以防止在 Objective-C 的全局命名空间中发生冲突。
类名和分类的左括号之间应有一个空格。
// GOOD:
// UIViewController+GTMCrashReporting.h
/** 一个为 UIViewController 添加崩溃报告元数据的分类。 */
@interface UIViewController (GTMCrashReporting)
/** 在崩溃报告中表示视图控制器的唯一标识符。 */
@property(nonatomic, setter=gtm_setUniqueIdentifier:) int gtm_uniqueIdentifier;
/** 返回视图控制器当前状态的编码表示。 */
- (nullable NSData *)gtm_encodedState;
@end如果一个类不与其他项目共享,则扩展它的分类可以省略名称前缀和方法名称前缀。
// GOOD:
/** 此分类扩展了一个不与其他项目共享的类。 */
@interface XYZDataObject (Storage)
- (NSString *)storageIdentifier;
@endObjective-C 方法名
方法名和参数名通常以小写字母开头,然后使用混合大小写。
应尊重正确的大写规则,包括名称开头。
// GOOD:
+ (NSURL *)URLWithString:(NSString *)URLString;方法名应尽可能像一个句子,这意味着你应该选择与方法名搭配流畅的参数名。Objective-C 的方法名往往很长,但这有一个好处,即一段代码几乎可以像散文一样阅读,从而使许多实现注释变得不必要。
仅在必要时在第二个及后续参数名中使用 “with”、“from” 和 “to” 等介词和连词,以阐明方法的含义或行为。
// GOOD:
- (void)addTarget:(id)target action:(SEL)action; // GOOD; 不需要连词
- (CGPoint)convertPoint:(CGPoint)point fromView:(UIView *)view; // GOOD; 连词阐明了参数
- (void)replaceCharactersInRange:(NSRange)aRange
withAttributedString:(NSAttributedString *)attributedString; // GOOD.如果方法返回接收者的某个属性,请以该属性命名方法。
// GOOD:
/** 返回此实例的 sandwich。 */
- (Sandwich *)sandwich; // GOOD.
- (CGFloat)height; // GOOD.
// GOOD; 返回值不是一个属性。
- (UIBackgroundTaskIdentifier)beginBackgroundTask;// AVOID:
- (CGFloat)calculateHeight; // AVOID.
- (id)theDelegate; // AVOID.访问器(Accessor)方法的命名应与其获取的对象相同,但不应以 get 作为前缀。例如:
// GOOD:
- (id)delegate; // GOOD.// AVOID:
- (id)getDelegate; // AVOID.返回布尔形容词值的访问器,其方法名以 is 开头,但这些方法对应的属性名省略 is。
点语法(Dot Notation)仅用于属性名,不用于方法名。
// GOOD:
@property(nonatomic, getter=isGlorious) BOOL glorious;
// 上述属性的 getter 方法为:
// - (BOOL)isGlorious;
BOOL isGood = object.glorious; // GOOD.
BOOL isGood = [object isGlorious]; // GOOD.// AVOID:
BOOL isGood = object.isGlorious; // AVOID.// GOOD:
NSArray<Frog *> *frogs = [NSArray<Frog *> arrayWithObject:frog];
NSEnumerator *enumerator = [frogs reverseObjectEnumerator]; // GOOD.// AVOID:
NSEnumerator *enumerator = frogs.reverseObjectEnumerator; // AVOID.有关 Objective-C 命名的更多详情,请参阅 Apple 的方法命名指南 。
这些指南仅适用于 Objective-C 方法。C++ 方法名继续遵循 C++ 风格指南中设定的规则。
函数名
函数名应以大写字母开头,每个新单词都以大写字母开头(即所谓的”驼峰命名法 ”或 “Pascal 命名法”)。
// GOOD:
static void AddTableEntry(NSString *tableEntry);
static BOOL DeleteFile(const char *filename);因为 Objective-C 不提供命名空间(Namespace),非静态函数应有一个前缀以减少命名冲突的可能性。
// GOOD:
GTM_EXTERN NSTimeZone *GTMGetDefaultTimeZone(void);
GTM_EXTERN NSString *GTMGetURLScheme(NSURL *URL);变量名
变量名通常以小写字母开头,使用混合大小写来分隔单词。
实例变量(Instance Variable)以下划线开头。文件作用域或全局变量以 g 为前缀。例如:myLocalVariable、_myInstanceVariable、gMyGlobalVariable。
通用变量名
读者应能从名称推断出变量类型,但不要使用匈牙利命名法(Hungarian Notation)来表示语法属性,如变量的静态类型(int 或指针)。
在方法或函数作用域外声明的文件作用域或全局变量(与常量不同)应该很少见,并且应有前缀 g。
// GOOD:
static int gGlobalCounter;实例变量
实例变量名使用混合大小写,并应以下划线作为前缀,如 _usernameTextField。
注意:Google 之前的 Objective-C 实例变量约定是使用尾部下划线。现有项目可以选择在新代码中继续使用尾部下划线,以保持项目代码库内的一致性。前缀或后缀下划线的一致性应在每个类内保持。
常量
常量符号(const 全局和静态变量以及用 #define 创建的常量)应使用混合大小写来分隔单词。
全局和文件作用域常量应有适当的前缀。
// GOOD:
/** GTL 服务错误的域。 */
GTL_EXTERN NSString *const GTLServiceErrorDomain;
/** GTL 服务错误代码的枚举。 */
typedef NS_ENUM(int32_t, GTLServiceError) {
/** 表示查询结果缺失的错误代码。 */
GTLServiceErrorQueryResultMissing = -3000,
/** 表示查询超时的错误代码。 */
GTLServiceErrorQueryTimedOut = -3001,
};因为 Objective-C 不提供命名空间,具有外部链接(External Linkage)的常量应有一个前缀以减少命名冲突的可能性,通常如 ClassNameConstantName 或 ClassNameEnumName。
为了与 Swift 代码的互操作性,枚举值的名称应是 typedef 名称的扩展:
// GOOD:
/** 支持的显示色调的枚举。 */
typedef NS_ENUM(int32_t, DisplayTinge) {
DisplayTingeGreen = 1,
DisplayTingeBlue = 2,
};小写的 k 可以用作在实现文件中声明的具有静态存储持续时间(Static Storage Duration)的常量的独立前缀:
// GOOD:
static const int kFileCount = 12;
static NSString *const kUserKey = @"kUserKey";注意:之前的约定是公共常量名以小写 k 开头,后跟项目特定的前缀。此做法不再推荐。