【问题标题】:Prefixing property names with an underscore in Objective C [duplicate]在Objective C中用下划线前缀属性名称[重复]
【发布时间】:2011-09-03 00:37:32
【问题描述】:

我以前避免在变量名中使用下划线,这可能是我大学 Java 时代的遗留问题。因此,当我在 Objective C 中定义一个属性时,我自然会这样做。

// In the header
@interface Whatever
{
    NSString *myStringProperty
}

@property (nonatomic, copy) NSString *myStringProperty;

// In the implementation
@synthesize myStringProperty;

但几乎在每个示例中都这样做

// In the header
@interface Whatever
{
    NSString *_myStringProperty
}

@property (nonatomic, copy) NSString *myStringProperty;

// In the implementation
@synthesize myStringProperty = _myStringProperty;

我是否应该克服对下划线的厌恶,因为这是它应该做的一种方式,这种风格是否有充分的理由成为首选?

更新:现在使用自动属性合成,您可以省略@synthesize,结果与您使用的一样

@synthesize myStringProperty = _myStringProperty;

这清楚地显示了您的 Apple 偏好。从那以后,我学会了停止担心并喜欢下划线。

【问题讨论】:

标签: iphone objective-c coding-style


【解决方案1】:

Apple 为他们自己的“私有”方法保留以下划线开头的选择器,其中包括属性。我认为他们不会为 ivar 名称保留 _。

就个人而言,我会避免使用下划线来启动任何类型的变量名。这是一个不透明的约定。如果其他人对局部变量使用下划线而对实例变量不使用下划线怎么办?如果您在定义了同名局部变量的方法中不小心省略了下划线怎么办?

最好将本地名称与 ivar 名称不同。例如,在 setter 中,您可能会使用 newName 或 newValue。

【讨论】:

  • 如果您投反对票,请有礼貌地发表评论
  • @Yar:你所说的“不再真实或从未如此”是什么?
  • @Yar 好的,在 2010 年我写这篇文章的时候,Apple 确实为它们的私有方法保留了前缀为下划线的选择器名称。事实上,我刚刚检查过,这仍然是真的。 developer.apple.com/library/mac/documentation/Cocoa/Conceptual/…
  • @Yar 我从来没有说过。
  • +1 很棒的东西(很抱歉我的困惑)!
【解决方案2】:

目前建议的 Objective-C 2.0 做法是为 ivar 使用与属性相同的名称。您可以选择在 @property 声明中分配不同的 ivar,但默认情况下,属性的合成访问器将访问与属性同名的 ivar,这表明这是他们希望您遵循的模式。

无论如何,由于对象仍然必须向自己发送消息以访问属性,因此在访问属性或直接访问其支持 ivar 时很难混淆,尽管使用 2.0 点访问属性确实使它更有可能。使用标准消息传递语法使意图更加明确,IMO。

@interface Foo : NSObject {
     NSNumber *bar;
} 
@property(readwrite, retain) NSNumber * bar
@end

@implementation Foo 
@synthesize bar;

-(void) baz {
   NSNumber *numberOne = [NSNumber numberWithInt: 1];   
   //Both set the value of bar through either the your custom or the synthesized setter method
   [self setBar:numberOne];  
   self.bar = numberOne; 

   //Both get the value of bar through your synthesized or your custom accessor method
   NSNumber *fooBar = [self bar];
   fooBar = self.bar;

   //Both manipulate the bar ivar directly
   bar = numberOne;
   fooBar = bar;
}
@end 

【讨论】:

    【解决方案3】:

    2012-02-16 修订后,Apple 在“Coding Guidelines for Cocoa”中明确说明了以 _ 为前缀的实例变量的命名约定,并说明了原因。

    确保实例变量的名称简洁地描述了存储的属性。通常,您不应直接访问实例变量,而应使用访问器方法(您确实在 init 和 dealloc 方法中直接访问实例变量)。为了帮助表明这一点,请在实例变量名称前加上下划线 (_),例如:

    @implementation MyClass {
        BOOL _showsTitle;
    }
    

    如果您使用声明的属性合成实例变量,请在 @synthesize 语句中指定实例变量的名称。

    @implementation MyClass
    @synthesize showsTitle=_showsTitle;
    

    https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/CodingGuidelines/Articles/NamingIvarsAndTypes.html#//apple_ref/doc/uid/20001284-BAJGIIJE

    斯坦福大学的 Paul Hegarty 在 iTunes U 中的讲座,iPhone App Development CS193p 2011 年秋季讲授,也解释了这一约定。

    http://itunes.apple.com/itunes-u/ipad-iphone-application-development/id473757255

    我知道这个问题是很久以前提出的,但我自己也有同样的问题并想分享我的发现。

    【讨论】:

      【解决方案4】:

      运行时的 KVC 部分在对对象使用 valueForKey: 时需要名称或 _name ivar,但它无法找到检索该变量的消息。见http://developer.apple.com/documentation/Cocoa/Conceptual/KeyValueCoding/Concepts/SearchImplementation.html

      如果运行时搜索 _name 并且苹果文档首先提到了 _name,那么这可能是有充分理由的。让我们来看看一些 SDK 类: UINavigationBar.h 这个类在所有 ivars 前面都有下划线,UIView 也是如此……不胜枚举。好吧,也许新奇的 iOS SDK 就是这样,而好的 ole NS* 类不会那样做……错了;他们在头文件中也使用下划线。

      Apple 在私有 API 消息和 ivars 中使用下划线。我不明白为什么他们的示例不推动这种行为,尤其是当运行时费心将这种所谓的“命名约定”硬编码到变量搜索路径中时。很高兴看到一些一致性。

      请注意,要符合 KVC,您必须遵循严格的命名方案;上面的链接可帮助您遵守这一点以使用运行时的这一方便功能。

      【讨论】:

        【解决方案5】:

        我只想指出,使用核心数据的新导航项目默认使用 trailing 下划线并将变量设为私有。

        @interface MyTestAppDelegate : NSObject <UIApplicationDelegate> {
        
            UIWindow *window;
            UINavigationController *navigationController;
        
        @private
            NSManagedObjectContext *managedObjectContext_;
            NSManagedObjectModel *managedObjectModel_;
            NSPersistentStoreCoordinator *persistentStoreCoordinator_;
        }
        
        @interface RootViewController : UITableViewController <NSFetchedResultsControllerDelegate> {
        
        @private
            NSFetchedResultsController *fetchedResultsController_;
            NSManagedObjectContext *managedObjectContext_;
        }
        

        【讨论】:

        • 良好的命名约定,即;最后下划线表示私有变量。
        【解决方案6】:

        我总是使用下划线。它在局部变量和实例变量之间建立了明显的区别。它还避免了以下情况下的编译器警告:

        @interface MyClass
        {
            NSString *name
        }
        
        @property (nonatomic, copy) NSString *name;
        
        - (id) initWithName:(NSString *) name;
        @end
        
        @implementation MyClass
        
        @synthesize name;
        
        // The following method will result in a compiler warning
        // (parameter name same as ivar name)
        - (id) initWithName:(NSString *) name {
           if (self = [super init]) {
              self.name = name;
           }
        
           return self;
        }
        
        @end
        

        编辑

        在不得不忍受投票和阅读 cmets 之后,让我尝试说明我的观点:

        Apple 建议 ivars 使用与其属性相同的名称。 Apple 还建议属性以小写字母开头。而且苹果还建议局部变量以小写字母开头。

        现在您遇到了一个问题,因为当您阅读一段代码时,您会看到正在使用的变量,您无法通过命名约定来判断该变量是 ivar 还是局部变量。太糟糕了。解决方案是对 ivars 和局部变量使用不同的命名约定。这只是普通常识。

        您实现此命名约定的方式无关紧要。如果你真的想要,你可以简单地将“_WOOHAHA”附加到 ivar 名称中。我不在乎(但也许其他人会)。问题是知道自己在做什么的人已经决定为 ivars 使用“下划线前缀”。恕我直言,他们做出了正确的决定,即使他们自己的公司推荐了其他东西。 (我所说的开发人员是编写一些主要的 Apple 框架和 .NET Framework 类的人)

        归根结底,代码质量比遵循甚至没有被宣扬它的人遵循的愚蠢规则更重要。


        关于您显示的代码的另一句话:永远不要在字符串属性上使用 retain。您应该改用 copy

        有关复制/保留属性的更多信息,请参阅:

        NSString property: copy or retain?

        【讨论】:

        • 不是那个。这是关于命名约定的。当您看到使用带有下划线前缀的变量的代码时,您会立即知道它是 ivar,而不是局部变量。 Apple 就是这样做的,而 Microsoft 在完整的 .NET 框架代码中使用此约定。
        • 我没有说这是一个标准。我说“我总是使用下划线,因为……”。我曾与苹果和微软一起宣扬有缺陷的编码实践。他们告诉我们以某种方式做事,但是对于他们自己的代码,他们使用不同的(更好的)标准。任何可以减少混淆并更好地理解/可读性的编码实践都是正确的选择。
        • @rano:在 C99 中,仅保留以下划线和 大写 字母开头的标识符,或以两个下划线开头的标识符。
        • 哦,顺便说一句,知道我在做什么,而且我不使用下划线前缀。此外,认为 Apple 工程师确实知道他们在做什么只是因为他们是 Apple 的假设是不安全的。
        • @JeremyP:你是对的,但是在作为 C 超集的语言中采用这种命名约定会导致代码的可读性降低。这是我一开始的观点,当时有人认为它对于与 ivars 不同的局部变量很有用,以避免编译器警告
        【解决方案7】:

        这纯粹是一个风格问题。

        我不知道哪些示例使用了带下划线的 ivar 样式。 Apple 的官方示例(例如 CryptoExercise)不使用 _ 作为 ivars 前缀。

        【讨论】:

        • Apple 将其用于自己的代码
        • @Phil:从未见过这些。但如果它们真的存在,那就意味着没有关于前导 _ 的 ivars 命名标准。
        • Google 的 Obj-C 风格指南采用了类似的方法,建议 ivars 使用尾随下划线 - google-styleguide.googlecode.com/svn/trunk/…
        • 检查 UIKit 的任何 UI*.h 文件。他们都使用下划线前缀作为私有 ivars。
        • @Philippe:那些类中的 ivar 不应该使用。哎呀,Apple甚至在内部使用私有API。重点是提供给第三方开发者的示例从不使用领先的_
        猜你喜欢
        • 2011-07-31
        • 2013-02-21
        • 2017-03-17
        • 2011-10-16
        • 1970-01-01
        • 2011-05-27
        • 1970-01-01
        相关资源
        最近更新 更多