注释
注释对于保持代码可读性至关重要。以下规则描述了你应该注释什么以及在哪里注释。但请记住:虽然注释很重要,但最好的代码是自文档化的。给类型和变量起有意义的名称比使用晦涩的名称然后试图通过注释来解释它们要好得多。
注意标点、拼写和语法;阅读写得好的注释比阅读写得差的注释容易得多。
注释应像叙述性文本一样可读,具有正确的大写和标点。在许多情况下,完整的句子比句子片段更具可读性。较短的注释,如代码行末尾的注释,有时可以不那么正式,但要使用一致的风格。
编写注释时,请为你的受众写作:下一个需要理解你代码的贡献者。慷慨一些——下一个人可能就是你自己!
文件注释
文件可以选择性地以其内容的描述开头。
每个文件可以按顺序包含以下项目:
- 如果需要,许可证样板。为项目使用的许可证选择适当的样板。
- 如果需要,文件内容的基本描述。
如果你对带有作者行的文件进行了重大更改,请考虑删除作者行,因为修订历史已经提供了更详细和准确的作者记录。
声明注释
每个非平凡的接口(Interface),无论公有还是私有,都应附带描述其用途及其在整体中如何配合的注释。
注释应用于文档化类、属性、实例变量、函数、分类、协议声明和枚举。
// GOOD:
/**
* 处理应用启动和关闭通知的 NSApplication 委托。
* 由主应用控制器持有。
*/
@interface MyAppDelegate : NSObject {
/**
* 正在进行的后台任务(如果有)。
* 初始化为 UIBackgroundTaskInvalid 值。
*/
UIBackgroundTaskIdentifier _backgroundTaskID;
}
/** 为应用创建和管理 fetcher 的工厂。 */
@property(nonatomic) GTMSessionFetcherService *fetcherService;
@end鼓励使用 Doxygen 风格的注释来注释接口,因为它们会被 Xcode 解析以显示格式化的文档。有多种 Doxygen 命令 可用;在项目内一致地使用它们。
如果你已经在文件顶部的注释中详细描述了某个接口,可以简单地声明”完整描述请参见文件顶部的注释”,但确保有某种形式的注释。
此外,每个方法都应有解释其功能、参数、返回值、线程或队列假设以及任何副作用的注释。公有方法的文档注释应放在头文件中,非平凡的私有方法的注释应紧接在方法之前。
使用描述形式(“打开文件”)而不是命令形式(“打开文件”)来编写方法和函数注释。注释描述函数的功能;它不是告诉函数该做什么。
记录类、属性或方法所做的线程使用假设(如果有)。如果一个类的实例可以被多个线程访问,请特别注意记录围绕多线程使用的规则和不变量。
属性和实例变量的任何哨兵值(Sentinel Value),如 NULL 或 -1,应在注释中记录。
声明注释解释方法或函数是如何使用的。解释方法或函数是如何实现的注释应放在实现处而不是声明处。
测试用例类和测试方法的声明注释可以省略,如果注释不会传达方法名之外的额外信息。测试中的工具方法或测试特定类(如辅助类)应添加注释。
实现注释
为棘手、微妙或复杂的代码段提供解释注释。
// GOOD:
// 在调用完成处理器之前将属性设置为 nil,
// 以避免重入导致回调被再次调用的风险。
CompletionHandler handler = self.completionHandler;
self.completionHandler = nil;
handler();当有用时,还可以提供关于曾经考虑或放弃的实现方法的注释。
行尾注释应与代码至少间隔 2 个空格。如果你在连续几行上有注释,将它们对齐通常更具可读性。
// GOOD:
[self doSomethingWithALongName]; // 注释前两个空格。
[self doSomethingShort]; // 更多间距以对齐注释。消歧符号
在需要避免歧义时,在注释中使用反引号或竖线来引用变量名和符号,优先于使用引号或在行内命名符号。
在 Doxygen 风格的注释中,优先使用等宽文本命令来标记符号,如 @c。
标记有助于在符号是一个常见单词时提供清晰度,否则该单词可能使句子看起来像是写得很差。一个常见的例子是符号 count:
// GOOD:
// 有时 `count` 会小于零。或者当引用已经包含引号的内容时
// GOOD:
// 记得调用 `StringWithoutSpaces("foo bar baz")`当符号不言自明时,不需要反引号或竖线。
// GOOD:
// 此类用作 GTMDepthCharge 的委托。Doxygen 格式也适用于标识符号。
// GOOD:
/** @param maximum @c count 的最大值。 */对象所有权
对于不由 ARC 管理的对象,当指针所有权模型超出最常见的 Objective-C 使用惯例时,应尽可能明确。
手动引用计数(Manual Reference Counting)
从 NSObject 派生的对象的实例变量被假定为被持有(Retained);如果它们不被持有,应在注释中标记为弱引用(Weak)或使用 __weak 生命周期限定符声明。
在 Mac 软件中,标记为 @IBOutlets 的实例变量例外,它们被假定为不被持有。
当实例变量是指向 Core Foundation、C++ 和其他非 Objective-C 对象的指针时,应始终用强引用(Strong)和弱引用注释来声明,以指示哪些指针被持有、哪些不被持有。Core Foundation 和其他非 Objective-C 对象指针需要显式内存管理,即使在使用自动引用计数构建时也是如此。
强引用和弱引用声明的示例:
// GOOD:
@interface MyDelegate : NSObject
@property(nonatomic) NSString *doohickey;
@property(nonatomic, weak) NSString *parent;
@end
@implementation MyDelegate {
IBOutlet NSButton *_okButton; // 普通 NSControl; 仅在 Mac 上隐式弱引用
AnObjcObject *_doohickey; // 我的 doohickey
__weak MyObjcParent *_parent; // 用于发回消息(拥有此实例)
// 非 NSObject 指针...
CWackyCPPClass *_wacky; // 强引用,某个跨平台对象
CFDictionaryRef *_dict; // 强引用
}
@end自动引用计数(Automatic Reference Counting)
使用 ARC 时,对象所有权和生命周期是显式的,因此自动持有的对象不需要额外的注释。