Objective-C 中的单下划线显然是保留给 Apple 的“内部”使用(并且在 Apple 声明之前可用于私有实例变量)。但为什么他们要在 iPhone 的 SQLiteBooks 示例中使用双下划线呢?请参阅摘自 MasterViewController.m 的这段代码:
+ (EditingViewController *)editingViewController {
// Instantiate the editing view controller if necessary.
if (__editingViewController == nil) {
__editingViewController = [[EditingViewController alloc] initWithNibName:@"EditingView" bundle:nil];
}
return __editingViewController;
}
在这个论坛上提到了双下划线的使用,因为它与 C 相关 - 它用于“编译器的内部使用”。我想我不明白这在这种情况下如何适用。
我的应用程序中需要一个 ViewController,其行为与 SQLiteBooks 示例项目中的 ViewController 非常相似,但这个双下划线让我感到困惑。
C 编译器和 Objective-C 编译器对待带前导下划线的变量名称与任何其他变量名称都没有任何不同。 单下划线或双前导下划线只是一个约定,并且有效地形成一个命名空间,非常类似于 Cocoa 类中使用的
NS
前缀,如 NSString
。
查看SQLiteBooks代码,
MasterViewController.m
定义了这个静态全局变量:
// Manage the editing view controller from this class so it can be easily accessed from both the detail and add controllers.
static EditingViewController *__editingViewController = nil;
所以我的猜测是SQLiteBooks的作者使用双前导下划线来表示全局变量。
C 编译器(以及扩展 Objective-C)保留以两个下划线和一个大写字母开头的名称供编译器供应商使用,为它们提供保留的命名空间以用于用于实现标准库或引入新的全局变量和函数非标准关键字,例如
__block
。
虽然 SQLiteBooks 代码在技术上是有效的,但在我看来,它很容易与保留的命名空间混淆。 如果您确实重用该代码,我建议您重命名该变量(Xcode 有一个非常好的重命名重构功能,可以自动为您完成此操作)。
对于编译器来说,下划线被视为任何字母字符。但更一般地说,下划线通常由语言扩展或大型库使用,以避免与用户代码发生冲突。
使用下划线是有问题的,因为许多团体尝试使用特定的下划线组合来保留每个名称。
Apple 传统上使用单个下划线前缀来表示私有实例变量(面向对象语言中的常见样式)。这意味着每个人都应该在他们的 ivars 前添加下划线前缀,直到 Apple 指出如果 Apple 决定更改其标头(也许您不应该这样做),在代码中使用下划线可能会与 Cocoa 发生冲突。因此,下划线前缀已成为“不建议”的编码实践。
在C和C衍生语言中,任何前后带有双下划线的单词都是非标准语言扩展。查看 Apple 的扩展,例如 __attribute__
尾随下划线通常作为编译器或调试器名称的原始名称的损坏版本添加(特别是当编译器是多遍时),并且通常会避免使用,以便这些名称与原始名称保持明显不同。 Google 在其 Objective-C 本地实例变量后面添加下划线,以避免与 Apple 的下划线发生冲突。
我的建议:不要使用下划线。您不应该使用与实例变量同名的局部变量(这只是令人困惑)。唯一潜在的冲突是 setter 方法中的参数与相应的实例变量之间 - 并且您可能应该在参数前面加上小写的“a”、“new”(或类似的),因为这清楚地指出该参数是传入值但还不是“那个”值。
这只是一个变量命名约定。它不做任何事情。这是程序编写者提醒自己的一种方式,“这是一个私有变量。”
编译器/库供应商将某些前置/后缀表示为“保留”的情况并不罕见。这很大程度上是为了避免类型/定义/继承变量之间出现任何无意的冲突。
您引用的帖子是关于定义的,而不是变量。许多编译器使用双下划线来表示它们提供和依赖的定义。
至于为什么示例代码使用这种风格 - 原作者使用了他在日常工作中可能使用的相同编码风格,并且从未强调潜在的冲突。
您应该可以按原样保留代码示例,但如果这让您感到不舒服,那么您可以重命名该变量。